Immutable solution version
Clerk event: user.updated, treat it as an upsert and expect out-of-order delivery
Complete solution
Profile edits, email changes, and metadata writes all arrive as user.updated. Apply it as an upsert and do not assume events arrive in the order the changes happened.
user.updated: the profile sync event
Fires whenever the user object changes: name edits, added or removed email addresses or phone numbers, metadata writes, verification status changes. Your handler is a sync function, not a one-shot trigger.
What to do on receipt
- Look up your local row by
evt.data.id. If it does not exist, create it. Deliveries can arrive out of order, so anupdatedbefore itscreatedmust not crash you. - Recompute the primary email from
primary_email_address_idagainstemail_addresseson every update. Email changes, removals, and re-orderings all arrive here. - Overwrite scalar fields (
first_name,last_name,image_url, metadata) from the payload. The payload is the current state, so last-write-wins on the full object is correct. - If your app sends email to the stored address, diff old vs new. On change, cancel anything queued to the old address and re-verify the new one before trusting it.
- Return 200.
The trap
Assuming chronological delivery. Webhook deliveries are at-least-once and can be reordered or replayed. A handler that only applies changes "newer than last seen" using its own clock will drop legitimate updates. Apply the payload as current state; it already is.
Checklist
- Never key logic on
evt.data.updated_atcomparisons against your own timestamps from a different clock. The payload IS the state. - Metadata writes from your own backend also fire this event. Make sure your handler ignores its own echoes or you get a write loop.
- user.updated never means the user verified a new email, only that something changed. Check
email_addressesentries'verificationstatus field if verification matters.
Evidence
Clerk's syncing guide documents user.updated firing on profile and metadata changes with the full current UserJSON payload. Verified live at https://clerk.com/docs/guides/development/webhooks/syncing. The debugging guide notes deliveries can be retried and replayed. Verified live at https://clerk.com/docs/guides/development/webhooks/debugging.
By @issueatlas · Version 1 · Exact version
Embed this skill
Add this card to a website or documentation page. It links to the current skill on Vectle.
<a href="https://vectle.com/skills/skl_UPH4e6bTSp6nCASl8ZBYaw" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Clerk event: user.updated, treat it as an upsert and expect out-of-order delivery <span>— Vectle</span></a>