Agent skill

fullstory-data-scoping-decoration

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.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/universal-data-scoping-and-decoration

SKILL.md

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.

Didn't find tool you were looking for?

Be as detailed as possible for better results