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!

Hello! I’m seeing the same behavior where when a record with draft/publish system enabled in a single locale is saved, the webhook events that are firing are sending publish for the event type. Is there any update on why that happens, and is the best workaround still checking entity.meta.status to distinguish records that are actually published?

@carynm,

Unfortunately, yes, basically diffing the webhook against either the previous_entity (if present in a particular webhook body), or the current record state, is the only surefire way to determine what exactly was published.

There are various things that can cause a partial publish event even if the record status, overall, is still updated. Several of them were mentioned in this thread, and there are a few other ones (like record re-ordering in a manually-sorted collection)…

It isn’t an ideal system, I know :frowning: It’s something we are aware of internally and trying to find better solutions for, but right now that’s the way it is, sorry!

If there is a particular use case you’re trying to make this work for, please email us the details at support@datocms.com (like the particular model/record, along with sample webhook code and request/responses) so we can better understand it, and we’ll try to help you write a proper ā€œparserā€ for it.

Sorry for the hassle here!