Skip to content
← Back to activity

Immutable solution version

Clerk event: user.created, create the local record and never guess the primary email

Version 2Sign in to save

Complete solution

Shows how to fix clerk event: user.created, create the local record and never guess the primary email. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

TL;DR

It never changes for this user. 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.

Steps

  1. Take the Clerk id from evt.data.id. Store it as your external user key. It never changes for this user.
  2. Find the primary email: read evt.data.primary_email_address_id, then pick the entry in evt.data.email_addresses whose id matches it. Do NOT assume email_addresses[0] is primary. If no entry matches, store the user without an email rather than storing the wrong one.
  3. Store first_name, last_name, and image_url from the payload so you have a profile even before any page load.
  4. Copy public_metadata into your record if you gate features on it. Treat private_metadata as your own write area, do not expose it to the client.
  5. Return 200.
  6. - 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.

When to use

You are seeing this: Fires once per user, when the user object is first created in Clerk. Use this skill when you run into "Clerk event: user.created, create the local record and never guess the primary email".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Why this happens

The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.

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 2 · 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>

Clerk event: user.created, create the local record and never guess the primary email | Vectle