Define a group once.
A “Beta testers” segment that every flag in the project can use, kept out of the config JSON in clear text.
1
Create the segment
In Flags › Segments, create “Beta testers” with one condition: email one_of_hashed and the testers' addresses. A segment's conditions are ANDed, like a rule's. Then use it in a flag: a rule with the condition user is in Beta testers, serving on.
import { Flags } from "@productcraft/flags";
const flags = new Flags(); // PRODUCTCRAFT_API_KEY + PRODUCTCRAFT_WORKSPACE_ID
declare const projectId: string;
declare const settingId: string;
declare const productionId: string;
// Confidential comparator: only hashes of these emails ship in the
// config JSON; the API keeps the cleartext encrypted for editing.
const beta = await flags.projects.segments.create(projectId, {
key: "beta_testers",
name: "Beta testers",
conditions: [
{ user: { attribute: "email", comparator: "one_of_hashed", values: ["ada@example.com", "grace@example.com"] } },
],
});
const current = await flags.settings.values.retrieve(settingId, productionId);
await flags.settings.values.replace(settingId, productionId, {
version: current.version,
value: false,
rules: [{ conditions: [{ segment: { segment_id: beta.id, comparator: "in" } }], serve: true }],
});2
Why hashed
With a *_hashed comparator the config JSON your apps download holds only salted SHA-256 hashes of the addresses, not the addresses. The API keeps the clear text encrypted so you can read and edit the list in the console, with flags.confidential.read. The salt ships in the same JSON, so a guessable address can still be found by trying candidates: see Confidential comparators.
3
Add a tester without retyping the list
Every stored list has a list_id. Send it back with values_add or values_remove and the API edits the stored clear text for you, so a script never needs to read the whole list:
import { Flags } from "@productcraft/flags";
const flags = new Flags(); // PRODUCTCRAFT_API_KEY + PRODUCTCRAFT_WORKSPACE_ID
declare const segmentId: string;
const segment = await flags.segments.retrieve(segmentId);
const condition = segment.conditions[0]!;
const listId = "user" in condition ? condition.user.list_id : undefined;
await flags.segments.update(segmentId, {
version: segment.version,
conditions: [
{ user: { attribute: "email", comparator: "one_of_hashed", list_id: listId, values_add: ["linus@example.com"] } },
],
});Every flag that uses the segment follows at once: one change, one new revision for each environment that uses it.
4
Rules of thumb
- Segments hold user conditions only: no segment inside a segment and no prerequisites, so they can never loop.
- A segment in use cannot be deleted (
409 SEGMENT_IN_USE); the segment page lists the flags that use it. - Editing a segment used in a protected environment needs
flags.protected.update. - Up to 20 segments per project, 20 conditions each.