Documentation

Quick Start

Get ShipSilently running in your application in under 5 minutes, install the SDK, initialize once, evaluate flags anywhere.

1. Install the SDK

Pick your package manager:

npm install @shipsilently/node
bun add @shipsilently/node
yarn add @shipsilently/node
pnpm add @shipsilently/node
View @shipsilently/node on npm

Using a different language or runtime? Jump straight to the matching guide:

2. Get an API key

Create a key in the dashboard under Environment → API keys. Keys look like sk_live_… and are scoped to a single environment: a key issued for development can only ever evaluate development's flags.

SDK keys are secrets. There is currently one kind of key, and it is a server key. Anything holding it can read every flag configuration in that environment, so keep it server-side. Browser and mobile clients should call your own backend, which evaluates flags and returns only the resolved values, see Browser usage.

3. Initialize the client

Initialize ShipSilently once at app startup, not on every request. The client caches evaluations in memory and refreshes them in the background.

flags.ts
// flags.ts — create one client at startup and reuse it for the process lifetime.
// The client holds an in-memory flag cache and (optionally) a background
// analytics buffer, so constructing one per request throws both away.
import { ShipSilentlyClient } from '@shipsilently/node';

export const flags = new ShipSilentlyClient({
  apiKey: process.env.SHIPSILENTLY_KEY!,
});

4. Evaluate a flag

Call evaluate() anywhere in your code. The third argument is the default, and it is also what fixes the return type, so useNewFlow is a boolean and heroVariant is a string, with no generics to write out and no casting.

checkout.ts
// One flag, one network call. The third argument is both the fallback AND the
// type source — `useNewFlow` is `boolean`, `heroVariant` is `string`, inferred
// with no generics to write out.
import { flags } from './client';

interface User {
  id: string;
  plan: string;
  country: string;
}

export async function renderCheckout(user: User) {
  const useNewFlow = await flags.evaluate(
    'new-checkout-v2',
    { userId: user.id, plan: user.plan, country: user.country },
    false,
  );

  const heroVariant = await flags.evaluate('hero-variant', { userId: user.id }, 'control');

  return { useNewFlow, heroVariant };
}
Tip: Context attributes like userId, plan, and country drive targeting rules and percentage rollouts. Pass whatever attributes are relevant for your flags. userId is special, it is the bucketing key for rollouts.

5. Verify it works

Every evaluation comes back with a reason explaining the decision. Fetch the whole set and inspect it to confirm your key, environment, and rules are wired up the way you expect:

terminal
curl -X POST https://api.shipsilently.com/v1/evaluate/batch \
  -H "X-API-Key: $SHIPSILENTLY_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "context": { "userId": "u_123" } }'

A flag_disabled reason means the kill switch is off; default means no rule matched. Both are working answers, not errors. See evaluation reasons.

Next steps

Ready to ship your first flag?

Open Dashboard