Attributes (Feature Flags)
Feature Flag projects manage user attributes from the Audiences > Attributes tab. An attribute is a fact about a visitor, such as their browser or their subscription plan, that you can target on in an audience rule. Attributes come in two kinds: 11 built-in keys every Feature Flag project starts with, and custom attributes you add yourself.
- The built-in attributes table. These 11 keys are always there and cannot be edited or deleted.
- Click Add Attribute to register a custom attribute of your own (steps below).
Built-in attribute keys
Every Feature Flag project starts with 11 attribute keys already registered, each with the right name and type set up. You do not have to define them yourself before using them in an audience condition.
No SDK fills in a value for these keys automatically today. Your own code works out each value: reading a browser's user agent, looking up a country, reading a screen size. It then passes the value in the evaluation context, under the exact key name shown below. A key you never pass is treated as missing, and a condition on it evaluates to false.
Available in both client-side and server-side SDKs
- browser: Browser name (Chrome, Firefox, Safari, etc.).
- browserVersion: Browser version string.
- os: Operating system (Windows, macOS, Linux, iOS, Android).
- osVersion: OS version string.
- deviceType: Device category: desktop, mobile, or tablet.
- country: Two-letter country code.
The examples on this page share this setup:
import { AvsbServer } from '@avsbhq/node'const client = new AvsbServer({ sdkKey: process.env.AVSB_SDK_KEY! })// Stand-ins for your own request and data layer. detectBrowser stands for// whatever user-agent parsing you use; it is not part of A vs B.declare const req: { headers: Record<string, string | undefined> }declare const detectBrowser: (userAgent: string | undefined) => { browser: string os: string deviceType: string}declare const user: { id: string subscription: { plan: string } company: { employeeCount: number }}declare const cart: { total: number }declare const session: { viewedSkus: string[] }declare const orders: { createdAt: Date }[]declare const customer: { lifetimeSpend: number }Attributes ride on the evaluation context alongside kind and key. Work out each value yourself and pass it under its key name:
const detected = detectBrowser(req.headers['user-agent'])client.getFlag('flag_key', false, { kind: 'user', key: user.id, browser: detected.browser, os: detected.os, deviceType: detected.deviceType,})Client-only attributes
- language: Browser language code (en-US, fr, de).
- timezone: IANA timezone (America/New_York).
- screenWidth: Screen width in pixels.
- screenHeight: Screen height in pixels.
- darkMode: Whether the user prefers dark color scheme.
A server request carries no screen size and no color-scheme preference. These five keys only make sense from a browser-based SDK such as @avsbhq/react.
A condition on a client-only attribute never matches in server-side SDK evaluations, because a server-side context never carries a value for it. The condition fails closed: it does not match, so the visitor falls through to your next rule or the default variation.
Custom attributes
Custom attributes represent properties from your application: user identity, subscription plan, feature entitlements, team membership, or any other data you want to target by.
Registering a custom attribute
- Go to Audiences > Attributes.
- Click "Add Attribute".
- Fill in the key (alphanumeric with underscores, e.g.
userId), display name, and type (String, Number, Boolean, or JSON). A description is optional. - For String attributes, you can add suggested values (e.g.
free,pro,enterprise). These appear as dropdown options in the audience builder.
If a value is refused, the reason appears under the field it belongs to, for example "Key must be alphanumeric with underscores". It clears as soon as you edit that field.
Creating attributes inline from the audience builder
You can also create a new attribute without leaving the audience you are building. When you add a Custom Attribute condition, the attribute picker has a + New attribute affordance at the bottom of the dropdown. Click it to open a small form and register the attribute. It is then auto-selected for the condition you were editing, with no round-trip to the Attributes tab.
Passing custom attributes in your code
client.getFlag('checkout_redesign', false, { kind: 'user', key: user.id, userId: user.id, plan: user.subscription.plan, companySize: user.company.employeeCount,})Attribute types and operators
Each attribute type supports different comparison operators in audience conditions:
- String: equals, does not equal, contains, does not contain, starts with, ends with, regex, in list, not in list, exists, does not exist.
- Number: equals, does not equal, greater than, less than, greater than or equal, less than or equal, exists, does not exist.
- Boolean: equals, does not equal, exists, does not exist.
- JSON: contains, does not contain, exists, does not exist.
Commerce attributes (server-side evaluation)
The Commerce Conditions (cart value, products viewed, purchase history) also work in feature-flag rules evaluated by server SDKs. A server has no browser storage or visitor profile lookup to draw on. So your code supplies the commerce data in the evaluation context, using these reserved attribute keys:
| Attribute | Type | Used by |
|---|---|---|
cartValue | number: the cart total as a decimal in the project currency (e.g. 49.99) | Cart value conditions |
viewedSkus | string[]: product SKUs the user has viewed | Products viewed conditions matching by SKU |
viewedCategories | string[]: product categories the user has viewed | Products viewed conditions matching by category |
purchaseHistory | object: { hasPurchased: boolean; lastPurchaseAt?: number; lifetimeSpend?: number; orderCount?: number } | Purchase history conditions |
purchaseHistory field details: lastPurchaseAt is epoch milliseconds; lifetimeSpend is a decimal amount in the project currency. Amounts you configured in the dashboard condition are compared against these decimals using the project currency's minor-unit rules: you never pass cents.
client.getFlag('free_shipping_banner', false, { kind: 'user', key: user.id, cartValue: cart.total, // 124.50 viewedSkus: session.viewedSkus, // ['SKU-001', 'SKU-204'] purchaseHistory: { hasPurchased: orders.length > 0, lastPurchaseAt: orders[0]?.createdAt.getTime(), lifetimeSpend: customer.lifetimeSpend, orderCount: orders.length, },})A missing or wrongly-typed attribute makes the condition evaluate to false: the same fail-closed behavior as every other attribute condition. Two behaviors deliberately differ from the browser snippet, and are worth knowing:
In the browser, "no profile found" is an authoritative answer (the visitor never purchased), so Has not purchased matches. On the server, an absent purchaseHistory attribute just means your code didn't provide it, so all purchase-history operators evaluate to false, including Has not purchased. To target never-purchasers server-side, pass it explicitly: purchaseHistory: { hasPurchased: false }.
Products-viewed conditions that reference a LIST dataset evaluate to false in server SDKs: the server SDK does not resolve dataset membership during flag evaluation. For server-evaluated rules, use conditions with a literal SKU/category list instead.
One more difference in kind rather than behavior: the snippet distinguishes the session window from the 30-day window automatically. A server SDK cannot: it checks whatever lists you pass as viewedSkus / viewedCategories, so the window is effectively whatever recency your code applies when building those arrays.
Deleting attributes
Custom attributes can be deleted from Audiences > Attributes. Built-in attributes cannot be deleted.
If a custom attribute is used in any audience condition, deletion is blocked. Remove the attribute from all audience conditions first, then delete it.