Introduction
The Extraction Rules API provides programmatic access to create, read, update, and archive extraction rules. Extraction rules define how Fullstory captures structured data from your website or app — pulling values from page elements, URLs, and other sources into named properties for analytics.
Authentication
The HTTP API requires an API key that you can generate from the Fullstory app. The API key must have Admin or Architect level permissions for mutation operations. The header value takes the form "Basic {YOUR_API_KEY}".
Security Scheme Type: | apiKey |
|---|---|
Header parameter name: | Authorization |
Extraction Rules API Overview
Extraction rules pull structured data from page elements, URLs, or static values into named properties for analytics and segmentation. Each rule has a source (where to look), a scope (where to write the result), and one or more mappings (what to extract).
The API is archive-only. ArchiveExtractionRule stops a rule from capturing data but preserves it for audit history; UnarchiveExtractionRule restores it. There is no public delete RPC — permanent deletion is intentionally UI-only.
Concepts
Source — where the data comes from
A rule has exactly one source:
element(ElementSource) — matches page elements by selector. Each selector targets one or moreplatformvalues (PLATFORM_WEB,PLATFORM_IOS,PLATFORM_ANDROID) and carries a platform-specific selector string: a CSS selector for web, the view class name for iOS, or the fragment class name for Android. Multiple selectors in one rule combine with OR semantics.url(UrlSource) — matches the page URL. Setany: trueto consider every URL; per-mapping URL component selection happens inUrlValue(see below).
Named elements. Some SCOPE_ELEMENT rules in your org may anchor on a named element (named_element_id or child_named_element_id). The public API surfaces those fields so existing rules round-trip through Get / List / PUT / PATCH. The rules:
- Creates always use selectors. Do not set
named_element_idorchild_named_element_idwhen creating a new rule. Configure named elements in Fullstory first if you need them. - Updates can drop, but not add, named-element anchoring. PATCH or PUT may replace named-element anchoring with selectors. They cannot introduce named-element anchoring on a rule that was stored without it — make that change in Fullstory.
SCOPE_PAGEandSCOPE_USERrules cannot use named-element anchoring at all. Settingnamed_element_idorchild_named_element_idon those scopes is rejected.
Scope — where the data goes
A rule has exactly one scope, applied to all of its mappings:
SCOPE_PAGE— writes to a page-scoped property (page name or a custom page property).SCOPE_USER— writes to a user-scoped property (uid, email, display name, or a custom user property).SCOPE_ELEMENT— writes to an element-scoped property. Element-scoped rules carry extra constraints; see below.
Constraints when scope is SCOPE_ELEMENT
SCOPE_ELEMENT rules have a few extra requirements that page- and user-scoped rules do not:
- Exactly one mapping per rule. A
SCOPE_ELEMENTrule must contain exactly onemappingsentry. - Element source only — no URL source. A
SCOPE_ELEMENTrule must read from a matched element. URL sources are not valid here. - Attribute-only mappings when the anchor is loose. When the element anchor is
match_any_selectoror carries achild_match, every mapping must read from an HTML attribute (element_value.attribute).inner_textandstatic_valueare not supported in those configurations. element_value.attribute.include_ancestorsis honored only onSCOPE_ELEMENTrules. When set, attribute resolution walks ancestors from the extraction basis and the nearest match wins.
Mapping — what to extract and where to write it
Each mapping has three parts:
- value source — exactly one of
element_value,url_value, orstatic_value.element_valuereads from the matched element. Useattributeto read an HTML attribute by name, or setinner_text: trueto read the element's text content.url_valuereads a piece of the URL. Set one of the boolean flagsfull,path,host, orfragmenttotrue, or set the string fieldqueryto the parameter name (for example"utm_campaign").static_valuewrites a fixed string regardless of page content.
- target — exactly one of the built-in Fullstory properties (
api_name,uid,email,display_name) or acustomPropertyidentified bynameanddata_type. - operation (optional) — a
ValueProducertransform applied to the raw value before it is written. Today the only supported transform is a regex (regex.expression, with an optionalregex.formatstring referencing capture groups like$1).
Active rule limits
Each org has a per-scope active_limit. Archiving a rule frees a slot; unarchiving consumes one. ListExtractionRules.usage_by_scope reports active_limit and active_count for each scope so callers can detect when an org is at the limit before attempting to create or unarchive.
Optimistic concurrency (etag)
Every rule has an opaque etag set by the server on read. Pass it on UpdateExtractionRule (PATCH) or Replace Extraction Rule (PUT). If the rule has changed since you read it, the server returns HTTP 409 Conflict — re-fetch, reconcile, and retry.
Updating rules: PATCH vs PUT
Two update endpoints sit on the same resource path:
PATCH /v2beta/extraction/rules/{id}(UpdateExtractionRule) — partial update. Send any subset ofname,description,source, andmappings; omitted fields stay as they are.sourceandmappingsare whole-field replacements when set: sending one mapping does not append, it overwrites the list.scopeis immutable on PATCH — to change it, archive the rule and create a new one.PUT /v2beta/extraction/rules/{id}(Replace Extraction Rule) — whole-resource replace. Send the complete rule body; every editable field is overwritten and unset fields are cleared.
Both honour the same etag flow. Choose PUT when you already hold the full intended rule state (for example, after editing it in your own UI). Choose PATCH when you only know the deltas.
PUT is friendly to a Get → mutate → PUT round-trip: server-managed fields on the rule body (created_at, updated_at, etag, archived) are silently ignored on input, so you can echo a Get response straight back without stripping fields. The body's id, if set, must agree with the id in the path.
Archive vs delete
This API is archive-only. ArchiveExtractionRule stops a rule from capturing data but preserves it for historical context. UnarchiveExtractionRule restores it (subject to active_limit). Permanent deletion is UI-only.
Unrepresented rules
Some legacy rules in an org cannot be modeled by the public API surface today. They count toward active_count but do not appear in the rules array. The unrepresented_count field on each scope in usage_by_scope reports how many rules matching this list request fall into that category. Manage those rules from the Fullstory UI.
Worked Example: Capture product price from a cart element
This rule watches the cart summary on the web app, reads the data-price attribute off the matched element, strips the leading currency symbol with a regex, and writes the result into a custom page-scoped property product_price of type DATA_TYPE_FLOAT.
{
"rule": {
"name": "Capture Product Price",
"description": "Extracts the product price from the cart summary element",
"scope": "SCOPE_PAGE",
"source": {
"element": {
"selectors": [
{
"platform": ["PLATFORM_WEB"],
"selector": "#cart-summary .price"
}
]
}
},
"mappings": [
{
"element_value": {
"attribute": {
"attribute": "data-price"
}
},
"target": {
"custom": {
"name": "product_price",
"data_type": "DATA_TYPE_FLOAT"
}
},
"operation": {
"regex": {
"expression": "^(\\d+\\.\\d{2})"
}
}
}
]
}
}
Worked Example: Capture campaign from URL query parameter
This rule reads the utm_campaign query parameter from any page URL and writes it into a custom user-scoped property acquisition_campaign of type DATA_TYPE_STRING.
{
"rule": {
"name": "Capture utm_campaign",
"description": "Reads the utm_campaign query parameter into a user property",
"scope": "SCOPE_USER",
"source": {
"url": {
"any": true
}
},
"mappings": [
{
"url_value": {
"query": "utm_campaign"
},
"target": {
"custom": {
"name": "acquisition_campaign",
"data_type": "DATA_TYPE_STRING"
}
}
}
]
}
}