SDK (@getenvie/client)
The typed client for the Envie API — one import, three auth modes, every surface. Start here.
@getenvie/client is the fastest way to integrate Envie: a typed, isomorphic client covering the storefront surface, identity, and the full private API.
npm i @getenvie/clientOne client, three modes
The mode decides where the client can run and what it may do — everything else is the same API.
| Mode | Runs in | Can | Setup |
|---|---|---|---|
proxy (default) | Liquid storefront browser | Read + toggle as the current shopper | Nothing — no keys |
public | Headless storefront browser | Read + toggle, anonymous scope | shop + publicKey |
private | Your server, only | Everything, incl. acting as a customer | shop + secretKey |
import { createEnvie } from "@getenvie/client";
// Liquid (theme) — served from the shop's own domain, signed by Shopify:
const envie = createEnvie();
// Headless browser — env_pk_… is browser-safe by design:
const enviePublic = createEnvie({
mode: "public",
shop: "your-store.myshopify.com",
publicKey: "env_pk_your_store_xxxxxxxx",
});
// Server — env_sk_… must never reach a browser:
const envieServer = createEnvie({
mode: "private",
shop: "your-store.myshopify.com",
secretKey: process.env.ENVIE_SECRET_KEY!,
});Keys come from the Shopify admin, Envie → Developers. The client also manages the shopper's
anonymous id, retries idempotent requests, and honors Retry-After on rate limits — you never
build a URL or header yourself.
The three surfaces
Storefront
envie.wishlist.* + subscribe() — read, toggle, share, and react to state. The shopper-facing
90%.
Identity & merge
identify() and the anonymous id — how a guest wishlist becomes the customer's at login.
Private surface
envie.private.* — shop, lists, analytics, exports/imports, webhooks, keys, settings.
Errors
Every non-2xx throws EnvieApiError carrying the HTTP status and the API's problem document. The
type URL is stable — branch on it, and open it in a browser for the fix:
import { createEnvie, EnvieApiError } from "@getenvie/client";
try {
await envie.wishlist.toggle({ productId: "8123456789012", handle: "soft-hoodie" });
} catch (error) {
if (error instanceof EnvieApiError) {
error.status; // 403
error.problem.type; // "https://docs.getenvie.com/errors/plan-limit"
error.problem.detail; // "The current plan allows 100 saved items. …"
}
}The full catalogue is in the error reference. Retries: idempotent GETs
retry automatically (default 2, configurable via retries); 429s wait out Retry-After.
All options
createEnvie({
mode: "proxy" | "public" | "private", // default "proxy"
shop: "your-store.myshopify.com", // required for public/private
publicKey: "env_pk_…", // public mode
secretKey: "env_sk_…", // private mode — server only
apiUrl: "https://api.getenvie.com", // override for tests
proxyBase: "/apps/envie", // proxy mode path, if you remapped it
anonymousId: "…", // explicit anonymous id (see Identity)
customerId: customer.id, // logged-in customer → one-shot merge
fetch: customFetch, // inject (tests, edge runtimes)
retries: 2, // idempotent-request retries
});Exhaustive type signatures live in the generated types appendix.