Jan 27, 2023



Jan 27, 2023

Refactoring our frontend API key: Familiar DX is the best DX

Colin Sidoti

Colin Sidoti

We switched to the familiar Publishable Key, but we changed less than you'd think

Like most other developer tools, Clerk's SDKs are configured with two "keys," one for the backend and one for the frontend.

And we share the same core requirements:

  • The backend key must have significantly random so it cannot be guessed
  • The frontend key is public, so it only needs to be a unique identifier

Although there's no security benefit in doing so, many tools have their frontend key mirror the format and length of their backend key. Take Stripe, for example:

Stripe API keys
(Don't worry, the secret key has been rolled.)

But as an authentication company, Clerk has an extra requirement for our frontend key, and it meant that mirroring our secret key would cause performance issues.

Wait, what? How could a key cause performance issues?

The purpose of a frontend key is to be a unique identifier when interacting with a frontend-facing API. Here's an example of how Stripe's SDK uses the publishable key:

Stripe frontend API request
That's the same publishable key as above!

Notice how this request is being sent to a domain? Stripe SDKs always make requests to, even if you're embedding their elements into your own website.

But since Clerk runs an authentication API and since we're responsible for maintaining sessions, we can't securely do the same. We need to set HttpOnly cookies from a first-party context, which means our API needs to be accessible through our customers' domains. (Developers configure this by setting a CNAME in their DNS records.)

When we launched, our frontend key was simply the hostname where our frontend API is hosted. Developers configured it like this in their React apps:

<ClerkProvider frontendApi="">

By passing the API hostname directly, we avoided making an extra, waterfalled API request to exchange a traditional random key with the hostname. This led to faster overall loading speeds.

But we hit an unexpected problem with this strategy: it really confused developers. It was a common complaint in friction logs, and when we watched developers integrate Clerk we could see the confusion wash over their face.

A hostname as a frontend key is completely unfamiliar, and no matter what we tried with design and naming, we couldn't get over the hurdle.

So this week, we finally threw in the towel. Our new frontend API keys look just like Stripes:

Clerk Publishable Key
Clerk's new publishable key

But we refuse to exchange developer experience for performance, so there's a not-so-secret subtlety to our new publishable key. Take a closer look:


Now, base64-decode the part after pk_test_:$

Indeed, we just base64-encoded the old value and started calling it a publishable key. We added a $ as a simple stop character so we can detect when keys are malformed.

As a final step, we changed the prop name for React:

<ClerkProvider publishableKey="pk_test_Y2xlcmsuZXhhbXBsZS5jb20k">

Quick, dirty, and a little silly – but it works! We haven't sacrificed performance and our new publishable key feels much more familiar. Developers have stopped raising their eyebrows and breeze through initial setup.

Clerk's logo

Start now,
no strings attached

Start completely free for up to 5,000 monthly active users and up to 10 monthly active orgs. No credit card required.

Start Building

Pricing built for
businesses of all sizes.

Learn more about our transparent per-user costs to estimate how much your company could save by implementing Clerk.

View pricing
Clerk's logo


The latest news and updates from Clerk, sent to your inbox.

Clerk logo

Clerk - Complete User Management


© 2023 Clerk Inc.


© 2023 Clerk Inc.