Skip to content

Clerk and other auth providers

With any auth provider, your app identifies and tracks where it learns that an account exists, from its server code. This guide shows where, then the optional user-created webhook, other providers, and two pitfalls. It builds on Track conversions, which gives routingcat.identify and routingcat.track.

Choose where to record the sign-up

  • Where your server creates its own record of the account, such as its user row after sign-up: identify, then track there, as Track conversions shows.
  • With no such place, as with Clerk alone: from a server route of yours, at the new user’s first signed-in page load. Nothing is set up at the provider, but a user who never loads a signed-in page is missed.
  • Also in the provider’s user-created webhook, if you want every sign-up: it needs its endpoint added in the provider’s dashboard. Both paths use the id signup:<user id>, so a sign-up that both record counts once.

Whichever you choose, identify at every sign-in too, so that the person’s other devices link to the account.

Record the sign-up at the first signed-in page load

The browser asks, and your server decides:

  1. In the browser, once a user is signed in, your app calls a server route of its own, such as POST /api/signup, at each sign-in and page load. To ask less often, it can remember in localStorage each user it reported, and ask again when a call fails.
  2. The route reads the signed-in user from your provider, on the server, never from the request’s body, so a browser can only report its own user. It identifies that user at each call: await routingcat.identify(event, user.id).
  3. When the user is new, created in the last seven days, the route also calls routingcat.track(event, 'signup', …), with signup:<user id> as its id, the user’s id as its accountId, and the time the provider created the user as its occurredAt.
  • A time in milliseconds goes in as a Date. RoutingCat reads a plain number as Unix seconds, and Clerk’s times are Unix milliseconds.
  • Seven days. A user created in the week before the install is recorded at their next signed-in page load, dated when they signed up. An older user signed up before RoutingCat, and records no sign-up.
  • The visitor is the one whose browser called the route, read from its cookie, so the route names none.

Add the user-created webhook

Optional. A webhook carries no visitor cookie, so the sign-up passes the visitor id to the provider, in metadata the sign-up can set: with Clerk, unsafeMetadata, holding the rc_vid cookie’s value. On the provider’s user-created event, a server route of yours verifies the webhook’s signature, then:

  1. identifies the new user with that visitor id: await routingcat.identify(event, user.id, { visitorId });
  2. calls routingcat.track(event, 'signup', …) under the same id as the first-load recording, signup:<user id>, with the user’s id as accountId, that visitorId, and the creation time as occurredAt.

In the provider’s dashboard, add an endpoint for that event at the route’s address, such as /api/webhooks/clerk, and keep its signing secret in your server’s environment. RoutingCat’s middleware or Worker passes your API routes on unchanged, so the webhook reaches your route as the provider sent it.

Record sign-ups with other providers

The same two paths work with any provider:

  • At the first signed-in page load, from your server’s own read of the signed-in user and of its creation time.
  • In its user-created webhook, with the visitor id carried through the sign-up. With Supabase, carry it in signUp’s options.data. OAuth sign-ups have no such field, so they rely on the first-load recording.

From a backend that isn’t your Nuxt app, send the identity link and the event through the HTTP events API, as Track conversions shows.

Avoid two pitfalls

  • Verification on another device. When email verification finishes on another device, identify at account creation, on the first device: that browser is the visitor who saw your pages.
  • Callbacks posted from another site, such as Sign in with Apple’s form_post, arrive without RoutingCat’s cookies, which are SameSite=Lax, so an identify there has no visitor id. Identify at the next page load instead, from the route your signed-in pages call. status reports such calls as identify without a visitor id.

Next