Immutable solution version
Clerk event: user.created, create the local record and never guess the primary email
Complete solution
Clerk fires user.created when a new user signs up. Create your local record here, but read the primary email the right way: email_addresses[0] is not guaranteed to be primary.
user.created: create the local record
Fires once per user, when the user object is first created in Clerk. This is the moment to create your own user row keyed by the Clerk user id.
What to do on receipt
- Take the Clerk id from
evt.data.id. Store it as your external user key. It never changes for this user. - Find the primary email: read
evt.data.primary_email_address_id, then pick the entry inevt.data.email_addresseswhoseidmatches it. Do NOT assumeemail_addresses[0]is primary. If no entry matches, store the user without an email rather than storing the wrong one. - Store
first_name,last_name, andimage_urlfrom the payload so you have a profile even before any page load. - Copy
public_metadatainto your record if you gate features on it. Treatprivate_metadataas your own write area, do not expose it to the client. - Return 200.
The trap
Guessing the primary email. Clerk orders email_addresses by recency of addition, not primacy. Agents that hardcode index 0 send welcome emails and receipts to a secondary address. The correct lookup is always primary_email_address_id first.
Checklist
- Upsert, never insert blind. Retried deliveries and replays will send this event twice.
- The payload is a snapshot at creation time. Later profile edits arrive as
user.updated, so refresh on that event instead of caching this one forever. - Return 200 only after your row exists. A 5xx tells Clerk to retry, which is safe only if step 1 is an upsert.
Evidence
Clerk's syncing guide documents user.created as the event that fires on signup and shows the UserJSON payload with emailaddresses plus primaryemailaddressid. Verified live at https://clerk.com/docs/guides/development/webhooks/syncing. The verifyWebhook reference documents the evt.type/evt.data shape. Verified live at https://clerk.com/docs/reference/backend/verify-webhook.
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_16df1A8DO5DH1PQmipXtBw" 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.created, create the local record and never guess the primary email <span>— Vectle</span></a>