diff --git a/modules/backend/src/main/scala/docspell/backend/ops/OJob.scala b/modules/backend/src/main/scala/docspell/backend/ops/OJob.scala
index a5d88d35..ba848c7f 100644
--- a/modules/backend/src/main/scala/docspell/backend/ops/OJob.scala
+++ b/modules/backend/src/main/scala/docspell/backend/ops/OJob.scala
@@ -83,7 +83,7 @@ object OJob {
               else
                 pubsub.publish1IgnoreErrors(
                   JobDone.topic,
-                  JobDone(job.id, job.group, job.task, job.args, JobState.Cancelled)
+                  JobDone(job.id, job.group, job.task, job.args, JobState.Cancelled, None)
                 )
           } yield JobCancelResult.removed
 
diff --git a/modules/restserver/src/main/scala/docspell/restserver/Subscriptions.scala b/modules/restserver/src/main/scala/docspell/restserver/Subscriptions.scala
index 8ffa7045..ced60b68 100644
--- a/modules/restserver/src/main/scala/docspell/restserver/Subscriptions.scala
+++ b/modules/restserver/src/main/scala/docspell/restserver/Subscriptions.scala
@@ -14,6 +14,8 @@ import docspell.pubsub.api.PubSubT
 import docspell.restserver.ws.OutputEvent
 import docspell.scheduler.msg.{JobDone, JobSubmitted}
 
+import io.circe.parser
+
 /** Subscribes to those events from docspell that are forwarded to the websocket endpoints
   */
 object Subscriptions {
@@ -27,7 +29,14 @@ object Subscriptions {
   def jobDone[F[_]](pubSub: PubSubT[F]): Stream[F, OutputEvent] =
     pubSub
       .subscribe(JobDone.topic)
-      .map(m => OutputEvent.JobDone(m.body.group, m.body.task))
+      .map(m =>
+        OutputEvent.JobDone(
+          m.body.group,
+          m.body.task,
+          parser.parse(m.body.args).toOption,
+          m.body.result
+        )
+      )
 
   def jobSubmitted[F[_]](pubSub: PubSubT[F]): Stream[F, OutputEvent] =
     pubSub
diff --git a/modules/restserver/src/main/scala/docspell/restserver/ws/OutputEvent.scala b/modules/restserver/src/main/scala/docspell/restserver/ws/OutputEvent.scala
index 5ac68c48..f41dd5de 100644
--- a/modules/restserver/src/main/scala/docspell/restserver/ws/OutputEvent.scala
+++ b/modules/restserver/src/main/scala/docspell/restserver/ws/OutputEvent.scala
@@ -40,12 +40,20 @@ object OutputEvent {
       Msg("job-submitted", task).asJson
   }
 
-  final case class JobDone(group: Ident, task: Ident) extends OutputEvent {
+  final case class JobDone(
+      group: Ident,
+      task: Ident,
+      args: Option[Json],
+      result: Option[Json]
+  ) extends OutputEvent {
     def forCollective(token: AuthToken): Boolean =
       token.account.collective == group
 
     def asJson: Json =
-      Msg("job-done", task).asJson
+      Msg(
+        "job-done",
+        Map("task" -> task.asJson, "args" -> args.asJson, "result" -> result.asJson)
+      ).asJson
   }
 
   final case class JobsWaiting(collective: Ident, count: Int) extends OutputEvent {
diff --git a/modules/scheduler/api/src/main/scala/docspell/scheduler/msg/JobDone.scala b/modules/scheduler/api/src/main/scala/docspell/scheduler/msg/JobDone.scala
index 61eff3f9..3bd79832 100644
--- a/modules/scheduler/api/src/main/scala/docspell/scheduler/msg/JobDone.scala
+++ b/modules/scheduler/api/src/main/scala/docspell/scheduler/msg/JobDone.scala
@@ -10,7 +10,7 @@ import docspell.common._
 import docspell.pubsub.api.{Topic, TypedTopic}
 
 import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder}
-import io.circe.{Decoder, Encoder}
+import io.circe.{Decoder, Encoder, Json}
 
 /** Message to notify about finished jobs. They have a final state. */
 final case class JobDone(
@@ -18,7 +18,8 @@ final case class JobDone(
     group: Ident,
     task: Ident,
     args: String,
-    state: JobState
+    state: JobState,
+    result: Option[Json]
 )
 object JobDone {
   implicit val jsonDecoder: Decoder[JobDone] =
diff --git a/modules/scheduler/impl/src/main/scala/docspell/scheduler/impl/SchedulerImpl.scala b/modules/scheduler/impl/src/main/scala/docspell/scheduler/impl/SchedulerImpl.scala
index c114e2bc..db6fc5f1 100644
--- a/modules/scheduler/impl/src/main/scala/docspell/scheduler/impl/SchedulerImpl.scala
+++ b/modules/scheduler/impl/src/main/scala/docspell/scheduler/impl/SchedulerImpl.scala
@@ -231,7 +231,7 @@ final class SchedulerImpl[F[_]: Async](
       _ <- Sync[F].whenA(JobState.isDone(finishState))(
         pubSub.publish1IgnoreErrors(
           JobDone.topic,
-          JobDone(job.id, job.group, job.task, job.args, finishState)
+          JobDone(job.id, job.group, job.task, job.args, finishState, result.json)
         )
       )
       _ <- Sync[F].whenA(JobState.isDone(finishState))(
diff --git a/modules/webapp/src/main/elm/App/Update.elm b/modules/webapp/src/main/elm/App/Update.elm
index 67b9f416..9ca103ed 100644
--- a/modules/webapp/src/main/elm/App/Update.elm
+++ b/modules/webapp/src/main/elm/App/Update.elm
@@ -314,13 +314,16 @@ updateWithSub msg model =
 
         ReceiveWsMessage data ->
             case data of
-                Ok (JobDone task) ->
+                Ok (JobDone details) ->
                     let
                         isProcessItem =
-                            task == "process-item"
+                            details.task == "process-item"
 
                         isDownloadZip =
-                            task == "download-query-zip"
+                            details.task == "download-query-zip"
+
+                        isAddonExistingItem =
+                            Data.ServerEvent.isAddonExistingItem model.itemDetailModel.detail.item.id details
 
                         newModel =
                             { model
@@ -337,6 +340,9 @@ updateWithSub msg model =
                     else if Page.isDashboardPage model.page && isProcessItem then
                         updateDashboard texts Page.Dashboard.Data.reloadDashboardData newModel
 
+                    else if Page.isDetailPage model.page && isAddonExistingItem then
+                        updateItemDetail texts (Page.ItemDetail.Data.ReloadItem True) newModel
+
                     else
                         ( newModel, Cmd.none, Sub.none )
 
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/AddFilesForm.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/AddFilesForm.elm
index 8f6b3baf..074b6a31 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/AddFilesForm.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/AddFilesForm.elm
@@ -76,7 +76,7 @@ view texts model =
             , a
                 [ class S.successMessageLink
                 , href "#"
-                , onClick ReloadItem
+                , onClick (ReloadItem False)
                 ]
                 [ text texts.refreshNow
                 ]
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm
index e01db9d7..8f33119e 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Model.elm
@@ -281,7 +281,7 @@ initSelectViewModel =
 
 type Msg
     = ToggleMenu
-    | ReloadItem
+    | ReloadItem Bool
     | Init
     | SetItem ItemDetail
     | SetActiveAttachment Int
diff --git a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
index 48871ecb..5128c5c9 100644
--- a/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
+++ b/modules/webapp/src/main/elm/Comp/ItemDetail/Update.elm
@@ -387,12 +387,22 @@ update inav env msg model =
             resultModel
                 { model | menuOpen = not model.menuOpen }
 
-        ReloadItem ->
+        ReloadItem withFile ->
             if model.item.id == "" then
                 resultModel model
 
             else
-                resultModelCmd ( model, Api.itemDetail env.flags model.item.id GetItemResp )
+                resultModelCmd
+                    ( model
+                    , Cmd.batch
+                        [ Api.itemDetail env.flags model.item.id GetItemResp
+                        , if withFile then
+                            Ports.refreshFileView "ds-pdf-view-iframe"
+
+                          else
+                            Cmd.none
+                        ]
+                    )
 
         FolderDropdownMsg m ->
             let
@@ -1002,7 +1012,7 @@ update inav env msg model =
 
         DeleteAttachResp (Ok res) ->
             if res.success then
-                update inav env ReloadItem model
+                update inav env (ReloadItem False) model
 
             else
                 resultModel model
diff --git a/modules/webapp/src/main/elm/Data/ServerEvent.elm b/modules/webapp/src/main/elm/Data/ServerEvent.elm
index 57320996..b7d68d75 100644
--- a/modules/webapp/src/main/elm/Data/ServerEvent.elm
+++ b/modules/webapp/src/main/elm/Data/ServerEvent.elm
@@ -5,7 +5,7 @@
 -}
 
 
-module Data.ServerEvent exposing (AddonInfo, ServerEvent(..), decode)
+module Data.ServerEvent exposing (AddonInfo, JobDoneDetails, ServerEvent(..), decode, isAddonExistingItem)
 
 import Json.Decode as D
 import Json.Decode.Pipeline as P
@@ -13,7 +13,7 @@ import Json.Decode.Pipeline as P
 
 type ServerEvent
     = JobSubmitted String
-    | JobDone String
+    | JobDone JobDoneDetails
     | JobsWaiting Int
     | AddonInstalled AddonInfo
 
@@ -26,6 +26,32 @@ type alias AddonInfo =
     }
 
 
+type alias JobDoneDetails =
+    { task : String
+    , args : Maybe D.Value
+    , result : Maybe D.Value
+    }
+
+
+{-| Return wether the job done details belong to running an addon of
+that item with the given id.
+-}
+isAddonExistingItem : String -> JobDoneDetails -> Bool
+isAddonExistingItem itemId details =
+    let
+        itemIdDecoder =
+            D.field "itemId" D.string
+
+        -- This decodes the structure from scalas ItemAddonTaskArgs (only itemId)
+        decodedId =
+            Maybe.map (D.decodeValue itemIdDecoder) details.args
+                |> Maybe.andThen Result.toMaybe
+    in
+    details.task
+        == "addon-existing-item"
+        && (itemId /= "" && decodedId == Just itemId)
+
+
 addonInfoDecoder : D.Decoder AddonInfo
 addonInfoDecoder =
     D.succeed AddonInfo
@@ -51,8 +77,7 @@ decodeTag : String -> D.Decoder ServerEvent
 decodeTag tag =
     case tag of
         "job-done" ->
-            D.field "content" D.string
-                |> D.map JobDone
+            D.field "content" (D.map JobDone decodeJobDoneDetails)
 
         "job-submitted" ->
             D.field "content" D.string
@@ -68,3 +93,11 @@ decodeTag tag =
 
         _ ->
             D.fail ("Unknown tag: " ++ tag)
+
+
+decodeJobDoneDetails : D.Decoder JobDoneDetails
+decodeJobDoneDetails =
+    D.map3 JobDoneDetails
+        (D.field "task" D.string)
+        (D.field "args" (D.maybe D.value))
+        (D.field "result" (D.maybe D.value))
diff --git a/modules/webapp/src/main/elm/Page.elm b/modules/webapp/src/main/elm/Page.elm
index 5799fdac..69adaa4a 100644
--- a/modules/webapp/src/main/elm/Page.elm
+++ b/modules/webapp/src/main/elm/Page.elm
@@ -14,6 +14,7 @@ module Page exposing
     , hasSidebar
     , href
     , isDashboardPage
+    , isDetailPage
     , isOpen
     , isSearchPage
     , isSecured
@@ -175,6 +176,16 @@ isDashboardPage page =
             False
 
 
+isDetailPage : Page -> Bool
+isDetailPage page =
+    case page of
+        ItemDetailPage _ ->
+            True
+
+        _ ->
+            False
+
+
 pageName : Page -> String
 pageName page =
     case page of
diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm
index 3d0111a4..2133f697 100644
--- a/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm
+++ b/modules/webapp/src/main/elm/Page/ItemDetail/Data.elm
@@ -38,6 +38,7 @@ type Msg
     | ItemResp (Result Http.Error ItemDetail)
     | ScrollResult (Result Dom.Error ())
     | UiSettingsUpdated
+    | ReloadItem Bool
 
 
 type alias UpdateResult =
diff --git a/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm
index f8ef0541..5547a169 100644
--- a/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm
+++ b/modules/webapp/src/main/elm/Page/ItemDetail/Update.elm
@@ -47,6 +47,13 @@ update inav env msg model =
             , selectedItems = env.selectedItems
             }
 
+        ReloadItem withFiles ->
+            let
+                m =
+                    ItemDetailMsg (Comp.ItemDetail.Model.ReloadItem withFiles)
+            in
+            update inav env m model
+
         ItemDetailMsg lmsg ->
             let
                 result =
diff --git a/modules/webapp/src/main/elm/Ports.elm b/modules/webapp/src/main/elm/Ports.elm
index 09ff2b44..61c5d99e 100644
--- a/modules/webapp/src/main/elm/Ports.elm
+++ b/modules/webapp/src/main/elm/Ports.elm
@@ -11,6 +11,7 @@ port module Ports exposing
     , printElement
     , receiveCheckQueryResult
     , receiveServerEvent
+    , refreshFileView
     , removeAccount
     , setAccount
     , setUiTheme
@@ -54,6 +55,11 @@ port printElement : String -> Cmd msg
 port receiveWsMessage : (D.Value -> msg) -> Sub msg
 
 
+{-| Given an ID of an element that is either EMBED or IFRAME the js will reload its src
+-}
+port refreshFileView : String -> Cmd msg
+
+
 
 --- Higher level functions based on ports
 
diff --git a/modules/webapp/src/main/webjar/docspell.js b/modules/webapp/src/main/webjar/docspell.js
index 3176e162..8a9d24f6 100644
--- a/modules/webapp/src/main/webjar/docspell.js
+++ b/modules/webapp/src/main/webjar/docspell.js
@@ -121,6 +121,16 @@ elmApp.ports.printElement.subscribe(function(id) {
     }
 });
 
+elmApp.ports.refreshFileView.subscribe(function(id) {
+    var el = document.getElementById(id);
+    if (el) {
+        var tag = el.tagName;
+        if (tag === "EMBED" || tag === "IFRAME") {
+            var url = el.src;
+            el.src = url;
+        }
+    }
+});
 
 var dsWebSocket = null;
 function closeWS() {
@@ -146,6 +156,8 @@ function initWS() {
         }
     });
 }
+
+// Websockets are not used yet for communicating to the server
 // elmApp.ports.sendWsMessage.subscribe(function(msg) {
 //     socket.send(msg);
 // });