identify is the handshake that tells Meridian a shop exists. It upserts the install, returns the shop token your app needs, and is where you hand over what you know about the merchant.
Most apps never call it directly. createMeridianApp’s mintShopToken is the same call with the environment already wired in: it fills the developer database tag for you and caches the handshake, so repeats cost nothing. The admin client is the lower-level path, and it is raw: every call reaches Meridian and counts against your rate budget.
setCustomFields. See Custom field values.
What identify takes
It returns
{ shopToken, shopTokenExpiresAt, customer }. That customer is identity only and carries no custom field values. Read those from getCustomer() or useMeridian().customer.
Calling identify again for the same shop returns its current token rather than creating a second install, so a repeat is always safe. It is not free, though: through the raw admin client every call is a request against your 120-per-minute budget. Call it through mintShopToken, where a repeat with the same payload is served from memory for the token’s lifetime, or persist the token and skip the call entirely while it is live.
Identify also asks Shopify for the shop’s contact email, its storefront’s primary domain, its country and language, and its billing currency, as best-effort enrichment. All of them need Meridian to reach your app’s session store, so on an app not hosted on Meridian the email, domain, country and language go unresolved and the currency falls back to USD, which prices every plan in dollars for a shop that bills in something else. The handshake itself still succeeds.
On such an app, pass the shop’s address in email yourself. It’s the only way Meridian learns it, and it’s where a Send email step addressed to the store sends, including the welcome email of an install automation.
The primary domain is what your CRM shows for the store (28collectionz.com rather than vyeiyd-4i.myshopify.com), and it refreshes on every handshake, so a merchant who changes domain is followed. A store with no custom domain keeps showing its .myshopify.com one.
The country is the one on the merchant’s Shopify shop address, stored as a two-letter ISO 3166-1 code, and the language is the store’s primary locale (en, pt-BR). Both show on the store’s profile in your CRM and both are available to automations and emails as store_country and store_language. See Variables.
Identify is the only place a store’s country comes from. A store Meridian knows only from the Partner API, because it installed your app before you shipped the SDK and has not opened it since, has no country at all: the Partner API’s shop object carries no address to read one from. The language needs one thing more, the read_locales scope on your app, without which it stays empty on a store that otherwise identifies normally.
Neither is ever cleared once known. A lookup that fails leaves the last value in place, so one bad round trip to Shopify can’t blank a field your automations branch on.
Contacts
The only address Shopify’s API gives you is the shop’s generic inbox, which belongs inemail. contacts is for the staff members who actually use your app.
email (required), firstName, lastName, phone and a free-form role.
Meridian keys contacts by email within an install, so re-sending the same person updates them rather than duplicating them, and a field you omit keeps its previous value. Contacts are additive: email stays the shop-level fallback.
Send them whenever you know who the user is: from an online access token’s associated_user block, or your own onboarding form. They appear in the CRM alongside anyone captured automatically.
Automatic contact capture
If you do not know who your users are, Meridian finds out. In an embedded app with App Bridge v4 loaded, the SDK reads the current staff member’s session token and forwards it to Meridian, which verifies it against your Shopify client secret, exchanges it for an online access token to read theassociated_user block, then discards that token.
Two things have to be true:
- Something calls capture from the browser:
MeridianProvider, orcaptureCurrentUserif you do not mount the provider. Both are described below. - Your Shopify client id and client secret are set on the app in Meridian, in App Settings under Meridian SDK. Meridian needs them to verify and exchange the token, so they are required for capture whatever your billing or hosting setup. Without both, capture does nothing, and the Meridian SDK section shows a notice saying so.
contacts, so the two paths never duplicate each other, and Meridian throttles to one capture per person per shop per day.
Shopify flags collaborators (agencies and freelancers), and Meridian stores them like anyone else, keeping the flag. Staff who reach the store through a Dev Dashboard collaboration are not flagged today: they arrive as plain users, so they show as User rather than Collaborator and are not excluded from automation sends the way collaborators are.
The SDK never sees your Shopify client secret. It forwards the session token; verification and the exchange happen on Meridian’s side. The SDK does not decode the token either.
With the provider
MountingMeridianProvider is the whole integration. It captures on mount, once per page load, and when it rotates an expired shop token it captures again with the new one, so a capture is never lost to an expired token.
Without the provider
An app that uses the SDK server-side only (identify, track, feature checks) never mounts the provider, and nothing captures on its behalf. Call captureCurrentUser yourself, once per page load, from the embedded layout:
shopToken is the token your loader minted with mintShopToken or identify, the same one you would pass to the provider. The call resolves silently in every failure mode and remembers, for the lifetime of the page, which shop tokens it has already answered for, so calling it from a component that remounts costs nothing.
Unlike the provider, the standalone call does not refresh an expired shop token. A capture refused for that reason is simply retried on the next page load, which is the right outcome when your loader mints the token per request.
Troubleshooting
Open the Network tab in the embedded app and look for the request tocontacts/capture.
Meridian records every
409 and 401 on its side too, so if the table does not settle it, support can tell you which state your app is in.