Strategic meta-skill for Fullstory data semantic decoration. Teaches when to use page properties vs element properties vs user properties vs events. Provides a deterministic framework for scoping data at the right level to maximize searchability, avoid duplication, and maintain consistency. Essential foundation for proper Fullstory implementation across all API types.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: fullstory-data-scoping-decoration
version: v2
description: Strategic meta-skill for Fullstory data semantic decoration. Teaches when to use page properties vs element properties vs user properties vs events. Provides a deterministic framework for scoping data at the right level to maximize searchability, avoid duplication, and maintain consistency. Essential foundation for proper Fullstory implementation across all API types.
related_skills:
- fullstory-page-properties
- fullstory-element-properties
- fullstory-user-properties
- fullstory-analytics-events
- fullstory-identify-users
- fullstory-getting-started
- fullstory-privacy-controls
- fullstory-privacy-strategy
- fullstory-banking
- fullstory-ecommerce
- fullstory-gaming
- fullstory-healthcare
- fullstory-saas
- fullstory-travel
- fullstory-media-entertainment
---
# Universal Data Scoping and Decoration: The Unified Model (v4.0)
> A deterministic strategy for applying high-signal data attributes across web interfaces. Separate user context from page context from element context to maximize efficiency, searchability, and consistency.
---
## Overview
This meta-skill provides the strategic framework for deciding **where** to capture data in Fullstory. Before implementing any Fullstory API, use this guide to determine the appropriate scope for your data.
### The Data Hierarchy
```
┌─────────────────────────────────────────────────────────────┐
│ USER PROPERTIES (FS setIdentity / setProperties) │
│ Scope: Across all sessions for this user │
│ Examples: plan, role, company, signup_date │
├─────────────────────────────────────────────────────────────┤
│ PAGE PROPERTIES (FS setProperties type: 'page') │
│ Scope: Current page until URL path changes │
│ Examples: pageName, searchTerm, filters, productId │
├─────────────────────────────────────────────────────────────┤
│ ELEMENT PROPERTIES (data-fs-properties-schema) │
│ Scope: Individual element interactions │
│ Examples: itemId, position, variant, price │
├─────────────────────────────────────────────────────────────┤
│ EVENT PROPERTIES (FS trackEvent) │
│ Scope: Single discrete action │
│ Examples: orderId, revenue, source, action │
└─────────────────────────────────────────────────────────────┘
```
---
## I. Core Principles: Data Scope and Responsibility
### Rule 1: Capture Data at the Highest Relevant Scope
**Why?**
- Reduces duplication
- Improves searchability
- Makes data inheritance work correctly
- Simplifies semantic decoration
**Decision Matrix:**
| Data Characteristic | Scope to Use | API |
|---------------------|--------------|-----|
| Same for all user sessions | User Properties | `setIdentity` / `setProperties(user)` |
| Same for entire page | Page Properties | `setProperties(page)` |
| Different per element on page | Element Properties | `data-fs-*` attributes |
| Discrete action/moment | Event | `trackEvent` |
### Rule 2: Never Duplicate Across Scopes
❌ **BAD**: Product ID on page AND on every element
```javascript
// Page properties
FS('setProperties', { type: 'page', properties: { productId: 'SKU-123' }});
// Also on element (REDUNDANT!)
<button data-product-id="SKU-123">Add to Cart</button>
```
✅ **GOOD**: Product ID at page level only
```javascript
// Page properties (single source of truth)
FS('setProperties', { type: 'page', properties: { productId: 'SKU-123' }});
// Element just has element-specific data
<button data-fs-element="Add to Cart Button">Add to Cart</button>
```
### Rule 3: Let Inheritance Work
Fullstory's property inheritance:
- **User properties** → Available on all sessions for that user
- **Page properties** → Available on all elements/events on that page
- **Element properties** → Inherited by child elements, AND child properties bubble up to parent on interaction
**Important: Child → Parent Inheritance**
When a user interacts with a parent element (e.g., clicks a form submit button), Fullstory captures properties from ALL child elements that have been interacted with:
```html
<form data-fs-element="CheckoutForm">
<select data-fs-element="ShippingMethod"
data-fs-properties-schema='{"value": {"type": "str", "name": "shipping"}}'>
<option value="standard">Standard</option>
<option value="express">Express</option>
</select>
<button type="submit">Place Order</button>
</form>
<!-- When form is submitted, Fullstory captures shipping selection from child -->
```
### Rule 4: Consider Privacy at Each Scope
Different scopes have different privacy implications:
| Scope | Privacy Consideration | Recommendation |
|-------|----------------------|----------------|
| **User Properties** | Persists across sessions, linked to identity | Hash/tokenize PII; use internal IDs |
| **Page Properties** | Visible in any session replay on this page | Mask sensitive page context |
| **Element Properties** | Captured on interaction | Use `fs-exclude` for sensitive inputs |
| **Events** | Logged with timestamp | Never include PII in event properties |
```javascript
// ✅ GOOD: Privacy-conscious scoping
FS('setIdentity', {
uid: 'usr_abc123', // Internal ID, not email
properties: {
plan: 'enterprise',
account_age_days: 365
// NO: email, name, phone
}
});
FS('setProperties', {
type: 'page',
properties: {
pageName: 'Account Settings',
section: 'billing'
// NO: account balance, card details
}
});
```
> **Reference**: See `fullstory-privacy-controls` for fs-exclude/fs-mask/fs-unmask and `fullstory-privacy-strategy` for comprehensive privacy guidance.
### Rule 5: Anonymous Users Can Have Properties
User properties work for **anonymous users** (before `setIdentity` is called). Properties persist via the `fs_uid` first-party cookie and transfer when the user later identifies:
```javascript
// Anonymous user lands on site
FS('setProperties', {
type: 'user',
properties: {
landing_page: '/pricing',
referral_source: 'google_ads',
campaign: 'spring_promo'
}
});
// Later, user signs up - properties transfer automatically
FS('setIdentity', {
uid: 'usr_newuser123',
properties: {
signup_date: '2024-01-15'
}
});
// Now user has: landing_page, referral_source, campaign, AND signup_date
```
---
## II. Scope Selection by Scenario
### Scenario A: Single-Entity Detail Pages (1:1)
**Definition**: A page dedicated to one unique entity (product detail, flight itinerary, policy document).
**Strategy**: Entity attributes become **Page Properties**
```javascript
// ✅ CORRECT: Entity data at page level
FS('setProperties', {
type: 'page',
properties: {
pageName: 'Product Detail',
productId: 'SKU-123',
productName: 'Wireless Headphones',
category: 'Electronics',
price: 199.99,
inStock: true
}
});
// ✅ CORRECT: Elements just have element-specific data
<button data-fs-element="Add to Cart">Add to Cart</button>
<button data-fs-element="Buy Now">Buy Now</button>
```
```javascript
// ❌ WRONG: Entity data duplicated on elements
<button
data-fs-element="Add to Cart"
data-product-id="SKU-123" // REDUNDANT - already at page level
data-product-name="Wireless..." // REDUNDANT
>Add to Cart</button>
```
**Why This Works:**
- All interactions inherit product context
- Search by "clicks on Product Detail page where price > 100" works
- No duplication, cleaner implementation
---
### Scenario B: Multi-Entity Listing Pages (1:Many)
**Definition**: Pages showing multiple distinct entities (search results, product grid, job listings).
**Strategy**:
- Search/filter context → **Page Properties**
- Individual item context → **Element Properties**
```javascript
// ✅ CORRECT: Search context at page level
FS('setProperties', {
type: 'page',
properties: {
pageName: 'Search Results',
searchTerm: 'wireless headphones',
resultsCount: 50,
sortBy: 'relevance',
activeFilters: ['Electronics', 'In Stock']
}
});
```
```html
<!-- ✅ CORRECT: Item-specific data on elements -->
<div
data-product-id="SKU-123"
data-product-name="Wireless Headphones"
data-price="199.99"
data-position="1"
data-fs-properties-schema='{
"data-product-id": {"type": "str", "name": "productId"},
"data-product-name": {"type": "str", "name": "productName"},
"data-price": {"type": "real", "name": "price"},
"data-position": {"type": "int", "name": "position"}
}'
data-fs-element="Product Card"
>
...
</div>
```
```html
<!-- ❌ WRONG: Search context duplicated on elements -->
<div
data-product-id="SKU-123"
data-search-term="wireless headphones" <!-- REDUNDANT - page level -->
data-results-count="50" <!-- REDUNDANT - page level -->
>
```
---
### Scenario C: User Attributes
**Definition**: Data about WHO the user is (not what they're doing).
**Strategy**: Use **User Properties** via `setIdentity` or `setProperties(user)`
```javascript
// ✅ CORRECT: User attributes at user level
FS('setIdentity', {
uid: user.id,
properties: {
displayName: user.name,
email: user.email,
plan: 'enterprise',
role: 'admin',
companyName: user.company,
signupDate: user.createdAt
}
});
```
```javascript
// ❌ WRONG: User attributes in page/element properties
FS('setProperties', {
type: 'page',
properties: {
userPlan: 'enterprise', // WRONG SCOPE - use user properties
userRole: 'admin' // WRONG SCOPE
}
});
```
---
### Scenario D: Discrete Actions (Events)
**Definition**: Something that **happened** at a point in time.
**Strategy**: Use **trackEvent** with action-specific properties
```javascript
// ✅ CORRECT: Action captured as event
FS('trackEvent', {
name: 'Product Added to Cart',
properties: {
quantity: 2, // Action-specific
addedFrom: 'quick-view', // Action-specific
// productId inherited from page properties
// userId inherited from user properties
}
});
```
```javascript
// ❌ WRONG: Trying to track actions via properties
FS('setProperties', {
type: 'user',
properties: {
lastAddedProduct: 'SKU-123', // Events shouldn't be properties
lastAddedQuantity: 2,
lastAddedTime: Date.now()
}
});
```
---
## III. Decision Flowchart
```
START: You have data to capture
│
▼
Is this data about WHO the user is?
(plan, role, company, signup date)
│
YES ──┴── NO
│ │
▼ ▼
USER Is this a discrete action/moment?
PROPS (purchase, signup, feature used)
│
YES ──┴── NO
│ │
▼ ▼
EVENT Is this data the same for the entire page?
(search term, product on detail page)
│
YES ──┴── NO
│ │
▼ ▼
PAGE ELEMENT
PROPS PROPS
```
---
## IV. Common Patterns by Industry
> **Detailed guidance**: See industry-specific skills for comprehensive implementation patterns.
### E-commerce (`fullstory-ecommerce`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| User's loyalty tier | User Property | `setIdentity` |
| Search term | Page Property | `setProperties(page)` |
| Product ID (on PDP) | Page Property | `setProperties(page)` |
| Product ID (in grid) | Element Property | `data-fs-*` |
| Cart value | Page Property | `setProperties(page)` |
| Purchase completed | Event | `trackEvent` |
### SaaS (`fullstory-saas`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| User role | User Property | `setIdentity` |
| Team/org ID | User Property | `setIdentity` |
| Dashboard being viewed | Page Property | `setProperties(page)` |
| Report ID in list | Element Property | `data-fs-*` |
| Feature used | Event | `trackEvent` |
| Setting changed | Event | `trackEvent` |
### Media & Entertainment (`fullstory-media-entertainment`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| Subscriber status | User Property | `setIdentity` |
| Content category | Page Property | `setProperties(page)` |
| Content ID (on detail) | Page Property | `setProperties(page)` |
| Related content IDs | Element Property | `data-fs-*` |
| Video played | Event | `trackEvent` |
| Content shared | Event | `trackEvent` |
### Banking & Finance (`fullstory-banking`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| Account type | User Property | `setIdentity` |
| Current section | Page Property | `setProperties(page)` |
| Transaction type | Page Property | `setProperties(page)` |
| Account selector | Element Property | `data-fs-*` (ID only, mask details) |
| Transfer completed | Event | `trackEvent` (no amounts) |
| MFA step | Event | `trackEvent` |
### Gaming (`fullstory-gaming`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| Player tier (VIP status) | User Property | `setIdentity` |
| Game lobby section | Page Property | `setProperties(page)` |
| Active game ID | Page Property | `setProperties(page)` |
| Game tile in grid | Element Property | `data-fs-*` |
| Wager placed | Event | `trackEvent` (for compliance) |
| Game launched | Event | `trackEvent` |
### Healthcare (`fullstory-healthcare`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| User role (patient/provider) | User Property | `setIdentity` |
| Section (appointments, records) | Page Property | `setProperties(page)` |
| Flow step | Page Property | `setProperties(page)` |
| Form field (non-PHI only) | Element Property | `data-fs-*` + `fs-exclude` |
| Appointment scheduled | Event | `trackEvent` (no PHI) |
| Form submitted | Event | `trackEvent` (completion only) |
### Travel & Hospitality (`fullstory-travel`)
| Data Point | Scope | Implementation |
|------------|-------|----------------|
| Loyalty tier | User Property | `setIdentity` |
| Search criteria | Page Property | `setProperties(page)` |
| Selected flight/hotel | Page Property | `setProperties(page)` |
| Flight option in results | Element Property | `data-fs-*` |
| Booking completed | Event | `trackEvent` |
| Ancillary added | Event | `trackEvent` |
---
## V. Anti-Patterns to Avoid
### Anti-Pattern 1: Everything as User Properties
```javascript
// ❌ BAD: Transient state as user property
FS('setProperties', {
type: 'user',
properties: {
currentPage: '/checkout', // Should be page property
cartItems: 5, // Should be page property
lastClickedButton: 'submit' // Should be event
}
});
```
### Anti-Pattern 2: Everything as Events
```javascript
// ❌ BAD: State as events
FS('trackEvent', { name: 'User Is Premium', properties: {} }); // User property
FS('trackEvent', { name: 'Page Has 5 Results', properties: {} }); // Page property
```
### Anti-Pattern 3: Duplicating Hierarchy
```javascript
// ❌ BAD: Same data at multiple levels
FS('setIdentity', { uid: '123', properties: { plan: 'premium' }});
FS('setProperties', { type: 'page', properties: { userPlan: 'premium' }}); // DUP
FS('trackEvent', { name: 'Click', properties: { userPlan: 'premium' }}); // DUP
```
### Anti-Pattern 4: Over-Granular Element Properties
```javascript
// ❌ BAD: Too much data on elements when page context would work
<button
data-page-name="Checkout" // Should be page property
data-user-id="123" // Should be user property
data-cart-total="99.99" // Should be page property
data-fs-element="Submit">
```
---
## VI. Implementation Checklist
Before implementing, answer these questions:
- [ ] **Who is this data about?**
- The user → User Properties
- The page/context → Page Properties
- A specific element → Element Properties
- An action → Event
- [ ] **How long is this data relevant?**
- Entire user lifetime → User Properties
- This page view → Page Properties
- This interaction → Element/Event Properties
- [ ] **Is this data already available at a higher scope?**
- If yes → Don't duplicate, let inheritance work
- If no → Add at appropriate scope
- [ ] **Can this data be searched/segmented?**
- User properties → Segment users
- Page properties → Find sessions with this page context
- Element properties → Find clicks on elements with this data
- Events → Funnel analysis, conversion tracking
---
## VII. Related Skills
### Core API Skills
| API | Skill Document |
|-----|----------------|
| User Identification | `fullstory-identify-users` |
| User Properties | `fullstory-user-properties` |
| Page Properties | `fullstory-page-properties` |
| Element Properties | `fullstory-element-properties` |
| Events | `fullstory-analytics-events` |
| Privacy Controls | `fullstory-privacy-controls` |
### Industry Skills
| Industry | Skill Document |
|----------|----------------|
| Banking & Finance | `fullstory-banking` |
| E-commerce & Retail | `fullstory-ecommerce` |
| Gaming | `fullstory-gaming` |
| Healthcare | `fullstory-healthcare` |
| B2B SaaS | `fullstory-saas` |
| Travel & Hospitality | `fullstory-travel` |
| Media & Entertainment | `fullstory-media-entertainment` |
### Strategic Skills
| Topic | Skill Document |
|-------|----------------|
| Getting Started | `fullstory-getting-started` |
| Privacy Strategy | `fullstory-privacy-strategy` |
| Stable Selectors | `fullstory-stable-selectors` |
---
## VIII. Version History
- **4.0** (Current)
- Added YAML front matter for skill metadata
- Integrated with core skill documents
- Added decision flowchart
- Expanded industry-specific patterns
- Added explicit anti-patterns section
- Aligned format with element-properties skill
- **3.0**
- Generalized naming and examples
- Added explicit Good/Bad implementation guides
- Renamed properties for universal application
- **2.0**
- Merged Scoping and Element Naming into one unified document
---
## Key Takeaways for Agent
When helping developers with data scoping:
1. **Always ask first**:
- What data are you trying to capture?
- Is this about the user, the page, an element, or an action?
- Will this data be the same across multiple elements?
- Is this data sensitive? What privacy level is needed?
2. **Common mistakes to watch for**:
- User data in page properties
- Page-level data duplicated on elements
- Actions captured as properties instead of events
- Same data at multiple scopes
- PII in user properties without hashing
- Forgetting that anonymous users can have properties
3. **Golden rules**:
- Capture at the HIGHEST relevant scope
- Let inheritance do the work (both parent→child AND child→parent)
- User → Page → Element → Event (hierarchy)
- Don't duplicate across scopes
- Consider privacy at every scope
4. **Quick decision**:
- WHO = User Properties (works for anonymous users too!)
- WHERE = Page Properties
- WHAT (specific item) = Element Properties
- WHAT HAPPENED = Events
5. **Privacy quick reference**:
- Sensitive user data → Hash/tokenize or use internal IDs
- Sensitive page context → Consider masking
- Sensitive elements → Use `fs-exclude`
- Sensitive events → Never include PII in properties
---
*This meta-skill document provides strategic guidance for Fullstory data semantic decoration. Refer to individual API skill documents for detailed implementation examples.*
No comments yet. Be the first to comment!