Receiving webhook "publish" events when a record is saved via CMA

I am experiencing an issue with records that are currently published, but an unpublished change was made to the record that caused a “publish” webhook event to fire.

Steps to reproduce:

  1. Published a record
  2. Make modifications to the record via the CMA, but don’t publish those changes

The interface in DatoCMS still shows the record as having “unpublished changes”, but we receive webhooks telling us it was published.

Is this expected behavior? If so, how can one the system that is processing webhooks request know whether or not the changes it received were published or not? Is “status” a safe field to rely on for that information?

I ask because it is not always clear to me when loading records from the CMA whether a record has a published version or not. I’m guessing that the “published_at” field is the best way to tell as that seems to only be set if a record has a published version. My assumption is that if the “status” is “updated”, but the “published_at” meta field is set…then the record is “published” with “unpublished changes”. Is that a correct assumption?

Hey @jearle,

Could this be related to having multiple locales on that model? Each locale can be published individually. If that happens:

  • When the record is saved, it fires an update event with meta.status=updated
  • If one locale is selectively published but another one is still in draft, it fires a publish event but meta.status=updated
  • If all locales are published (ie the entire record has no more unpublished changes and is showing up green in the Dato UI), then it fires a publish event with meta.status=published

In general, status=updated means one or more locales has saved but unpublished changes. status=published means everything is published. You can use published_at to determine the last publish (of any locale), but that doesn’t tell you which locale changed. I think generally it’s clearer (easier to think about) if you just assume that status=updated means “the record is not fully published yet”. Then you can look through the changes and determine if anything should be rebuilt.

update events (but not publish events) will have a previous_entity property that you can diff against the current entity to determine what changed. If that’s not enough, you can make a CMA call in the webhook receiver to retrieve a specific record version: Retrieve a record version — Record version — Content Management API


Edit: If you can link to the specific webhook & model in question, we can take a deeper look with you too. Feel free to post it here, DM me, or email support@datocms.com (whichever you prefer)

We only have one locale for our project. I’ll DM you the models and webhooks in question.

Hi @jearle,

Our developer looked into this and identified several rarer situations where a publish webhook could be fired. I’m asking if any of these will explicitly cause an updated state, but in the meantime, do you think any of these could be likely culprits?

Events that triggers a publish webhooks on items:

  • publishing a record (obviously :D)
  • destroying a parent record in a tree-structure item type (this is not the case)
  • when the item has a published version and the customer changes some meta attribute (e.g. created_at time, first published_at time, the creator, the workflow stage, basically, everything that is present in the item right sidebar)**
  • when the item has a published version and the customer changes its position in a sortable or tree structure item type (this is not the case)
  • when a model is removed from a link/links/structured text field list of valid models. We have to cycle all over the versions and remove from those fields any reference to the removed model
  • when a block model is removed from a rich_text/single_block/structured_text field. We have to cycle all over the versions and remove from those fields any blocks of that removed block model (this may currently be bugged – we’re checking – but that’s the intent)
  • when the customer edits an upload contained in a published version and now the published version is not valid anymore (or becomes valid)
  • when the item has a published version and a textual field contains an absolute URL of an upload and the customer replace the assets with a new one, so we have to update the absolute URL in the version. This happens also when a customer activates a custom upload bucket (very rare case)
    - when the item has a published version and contains a link to another record via a link/links/structured_text field. If this field’s validation has a rule that says “when a linked item is destroyed (or unpublished), remove the reference” and the referenced record is being unpublished / destroyed, then we have to adjust the referencing item and trigger a publish event
  • when you destroy a model and its records are being linked by other items via link/links/structured_text fields. we have to remove those references and we have to trigger a publish event, if the updated item has a published version already

I’ll let you know if the dev is able to identify specific scenarios that cause both a publish event and an updated state.

From your list, I think these are possible:

  • when the item has a published version and the customer changes some meta attribute (we send a date/time for ‘first_published_at’ for most update requests via the content management API)
  • when a block model is removed from a rich_text/single_block/structured_text field. We have to cycle all over the versions and remove from those fields any blocks of that removed block model (due to limitations in how our legacy system works, we send a fresh block object instead of the block id when updating a record via the content management API. we don’t have a way to store/remember block ids in our system, so it just sends the whole block in case anything has changed)

Thank you, @jearle. I just wanted you to know that we’re still discussing this internally.

If this is a time-sensitive situation, I think that checking the item status on the publish webhook (i.e., making sure status is published instead of updated) should be a viable workaround for now.

But I’m still trying to understand why this behavior even exists, and once I find out, I’ll report back. Thanks for your patience with this and all the details!