We want access to the publish transactions - including those that have a later publish transaction for the same item(s) with the same result.

We've seen responses/answers in TREX that indicate it is not possible and we've seen posts that indicate it is possible. >>> Update: See answers below - we had misunderstood the second TREX response.

We understand that the GUI is intended to show only the latest DISTINCT transactions and we see that this is all we can retrieve using the API. But we want access to them all.

We've tried through the API and we've even watched the database records and the rows in the publish_transactions are physically removed (Tridion 2013 SP1 HR1).

So. Are the publish transaction rows moved into another table (that I've not seen) or is the definitive answer that they are, indeed, not available (in which case we continue with the course of some extension to record them in the first instance)

Our next step may well be to check with support or even TRACE the SQL and see what's happening but I was hoping some Tridionaut out there has also had to log all transactions for client audit reasons also.

It would also be interesting to know if the same situation exists in Web8.x so we can assess the impact of future upgrades also but I guess that's for another question.

3 Answers 3


Indeed, Publish Transactions get removed as soon as a new one for the same item/target gets in a "final" state (Succes/Warning/Error); the Publish Queue is intended as a queue, not an audit trail.

Audit trail functionality in general can be relatively easily added in an implementation using event handlers. You could use (Global) Application Data to store the audit trail records in the CM Database.

I think that what Nuno was referring to is that we keep Publish Transactions even if the source item is removed (this was changed in 2013 SP1 to make publishing of Bundles within a publishing workflow work properly).

  • That makes sense - thanks Rick. In terms of storage we're thinking of something more accessible (to external developers/apps) than App Data (such as external files or database) - the challenge also being not to drag publishing speeds through the floor (several thousand pages per bi-weekly release) but that's another story :) Sep 13, 2017 at 20:37
  • Indeed Rick, I re-read my post and it seems I was slightly misguided/confused about those changes implied at that time. The behavior today is still the same as before - last transaction for an item/target combination with a final state will stay, others will be removed
    – Nuno Linhares
    Sep 14, 2017 at 9:05
  • 2
    @Dylan..MarkSaunders - use Asynchronous events, see example here: github.com/NunoLinhares/tridion-2011-reporting/blob/master/…
    – Nuno Linhares
    Sep 14, 2017 at 9:23

We had similar needs not just for audit trail but from a business user perspective where the user wanted to know when an item is published by whom and to which targets etc.

We wrote event system code to subscribe to the

EventSystem.SubscribeAsync<PublishTransaction, SaveEventArgs>(OnPublishStatus_Initiated, EventPhases.Initiated); 

to capture the information. You can get all the information that you are looking for if you subscribe to this event and then capture it from the publish transaction.

It triggers on publish to capture the relevant information and and we add this information in a custom DB. We have also written a GUI extension to display the information which allows the user to select an item and then with our GUI extension we display the information that we captured for the item which includes which version which target, when, by whom, whether the transaction was successful or not.

Once you capture the information, you can use it as you wish though. This was done for Tridion 2013 SP1 and we are still on the same version.

  • Do note that Publish Transactions are saved many times during their lifecycle. If you want to capture (un-)publish actions, ypu can also use PublishOrUnpublishEventArgs (or one of its subclasses for publish and unpublish). Sep 15, 2017 at 7:48

I tested the Web 8.5 publishing transactions API with Tridion Core service and do not see the old transactions. The results look just like the GUI.

There may be , an as yet, new filter to twiddle to include the later publish transaction for the same item, but I have not found it.

Maybe the feature Nuno mentions was in the plan but got pulled.

Try for yourself with this core service example that uses GetSystemWideList with PublishTransactionsFilterData filer to retrieve Publish Transactions. <# Tool to view Tridion Publishing Queue Chris Mills [email protected] Capax Global 2015

        [Parameter(Mandatory=$False,HelpMessage="How many hours of Queue to show")]
        [string]$Starthours = 48,
        [Parameter(Mandatory=$False,HelpMessage="Grid title text")]
        [string]$GridTitle = "Publishing Transactions last $Starthours hours - Capax Tridion PowerShell Tools",
        [Parameter(Mandatory=$False,HelpMessage="File path for csv output file")]
        [string]$filepath= "c:\PublishingTransactions.csv"


Import-Module Tridion.ContentManager.Automation
Add-Type -assemblyName System.ServiceModel
$TridionHome = $env:TRIDION_CM_HOME # it moves in Web 8
Add-Type -Path "$TridionHome\bin\client\CoreService\Tridion.ContentManager.CoreService.Client.dll"

    $fqdn = "$env:computername"
    $serviceurl ="http://localhost/webservices/CoreService201603.svc/wsHttp"
    $binding = new-object System.ServiceModel.WsHttpBinding
    $binding.MaxBufferPoolSize = [int]::MaxValue
    $binding.MaxReceivedMessageSize = [int]::MaxValue
    $binding.ReaderQuotas.MaxArrayLength = [int]::MaxValue
    $binding.ReaderQuotas.MaxBytesPerRead = [int]::MaxValue
    $binding.ReaderQuotas.MaxNameTableCharCount = [int]::MaxValue
    $binding.ReaderQuotas.MaxStringContentLength = [int]::MaxValue
    #$binding.CloseTimeout = New-TimeSpan -Minutes 10
    #$binding.OpenTimeout = New-TimeSpan -Minutes 10
    #$binding.ReceiveTimeout = New-TimeSpan -Minutes 10
    #$binding.SendTimeout = New-TimeSpan -Minutes 10


    $endpoint = new-object System.ServiceModel.EndpointAddress $serviceurl

    $core = new-object Tridion.ContentManager.CoreService.Client.SessionAwareCoreServiceClient $binding,$endpoint

    [datetime]$dt = (Get-Date).AddDays(-$DaysToKeep)
    $utcdate = $dt.ToString("yyyy-MM-dd HH:mm:ss") 
    $sn = $MyInvocation.InvocationName

        $filter = New-Object Tridion.ContentManager.CoreService.Client.PublishTransactionsFilterData
        $filter.StartDate = (Get-Date).AddHours(-$Starthours)
        $filter.EndDate = (Get-Date).AddHours(+1)
        $filter.IsCompleted = $true
        $transactions = $core.GetSystemWideList($filter)
        $Exeption = $_.Exception.Message
        $Message = "Failed to read Publishing Transactions before $utcdate.$n $Exeption"
        Write-EventLog -LogName Tridion -eventID 100 -Source "Tridion Data" -EntryType Error -Category 0 -Message $Message 
        write-output $Message


    $outdata = @()
    $no = 1
    foreach($transaction in $transactions)

        $transactionDetail = [ordered]@{
            "No.#"          = $no++
            "Transaction" = $transaction.Id.Split("-")[1]
            "Name"          = $transaction.Title
            "Item"        = $transaction.Items.IdRef.Split(":")[1]
            "Target"        = $transaction.ListInfo.PublicationTargetTitle
            "Publication"   = $transaction.ListInfo.PublicationTitle
            "Path"          = $transaction.ListInfo.ItemPath
            "Action"        = if($transaction.ListInfo.PublishAction){"UnPublish"}else{"Publish"}
            "State"         = $transaction.State
            "Priority"      = $transaction.Priority
            "Date"          = $transaction.StateChangeDateTime.ToString("yyyy-MM-dd")
            "Time"          = $transaction.StateChangeDateTime.ToString("HH:mm:ss")
            "User"          = $transaction.Creator.Title.Split("\")[1]

        $outdata += New-Object PSObject -Property $transactionDetail   

      $outdata | Out-GridView -Title $GridTitle  -PassThru | Export-Csv -Path $filepath
  • This rings true to our observation of the specific database table too Chris. It will be good to understand from Support (ticket being raised) what the official line is for 2013 and Web8 and then to ensure that concurs with what we've seen in 2013 and you've noted for Web8.5 here :) Sep 13, 2017 at 20:04
  • Just saving the data in a database table is good but it API support to access the data would be better. :) Although I have been known to write extensive database queries to analyse clients content and performance problems before, I always like to use the official API rather than ad hoc SQL. Lets hope that there is an undiscovered API method. Sep 14, 2017 at 7:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.