The Microsoft Clarity RTD module collects behavioral signals from a self-contained DOM tracker and enriches bid requests with bucketed categorical features. Signals are compact string labels (e.g. "deep", "moderate", "high") — not raw numerics — making them directly usable in DSP targeting rules without additional processing.
Signals are written into global ORTB2 fragments, making them available to all bidders. Data is published through three complementary paths:
site.ext.data.msclarity — structured key-value featuresuser.data segments — ORTB2-native segments for DSPs and platforms like Microsoft Curatesite.keywords — keyword strings for adapters that consume keywords (e.g. AppNexus)The module also persists signals to localStorage for warm-start support — the first auction of a new page load can use recent (≤ 30 min) signals instead of empty defaults.
The Clarity JS tag is injected by default for analytics and session-recording functionality. Set params.injectClarity: false to opt out of automatic injection. Bid-enrichment signals are computed independently from DOM events regardless of whether the Clarity tag is present.
Build the MS Clarity RTD module into the Prebid.js package with:
gulp build --modules=rtdModule,msClarityRtdProvider,appnexusBidAdapter,msftBidAdapter
Use setConfig to instruct Prebid.js to initialize the MS Clarity RTD module, as specified below.
This module is configured as part of the realTimeData.dataProviders object:
pbjs.setConfig({
realTimeData: {
auctionDelay: 200,
dataProviders: [{
name: 'msClarity',
waitForIt: true,
params: {
projectId: 'abc123xyz', // Required: Clarity project ID
// injectClarity: false, // Optional: disable auto-injection (default: true)
targetingPrefix: 'msc' // Optional: keyword prefix (default: 'msc')
}
}]
}
});
Syntax details:
| Name | Type | Description | Notes |
|---|---|---|---|
| name | String | Real-time data module name | Always 'msClarity' |
| waitForIt | Boolean | Should be true if there’s an auctionDelay defined |
Optional. Default false |
| params | Object | ||
| params.projectId | String | Microsoft Clarity project ID | Required |
| params.injectClarity | Boolean | Automatically inject the Clarity JS tag if not already present | Optional. Default true |
| params.targetingPrefix | String | Prefix for keyword key-values in site.keywords |
Optional. Default 'msc' |
Note: The module automatically injects the Clarity JS tag unless params.injectClarity is explicitly set to false. To manage the Clarity tag yourself, set injectClarity: false and add the tag to your page before Prebid loads.
The module computes 11 features in two tiers:
These accumulate over the page session and are saved to localStorage for use in the first auction of subsequent page loads.
| Feature | Key | Values | Description |
|---|---|---|---|
| Engagement | engagement |
low, medium, high, very_high |
Composite: scroll + dwell + interaction − frustration |
| Dwell Time | dwell |
bounce, brief, moderate, long, extended |
Visibility-aware active dwell time |
| Scroll Depth | scroll |
none, shallow, mid, deep, complete |
High-water-mark page scroll depth |
| Frustration | frustration |
none, mild, moderate, severe |
Deduplicated rage clicks + exploratory clicks + scroll reversals |
| Interaction | interaction |
passive, light, moderate, active, intense |
Deliberate events per second of active time |
| Reading Mode | readingMode |
skim, scan, read |
Whether the user is reading steadily, scanning, or skimming |
| View Quality | viewQuality |
low, medium, high |
Composite of reading time, active time, and scroll depth |
These reflect the user’s instantaneous state when a bid request fires. They are not persisted.
| Feature | Key | Values | Description |
|---|---|---|---|
| Activity Recency | activityRecency |
live, recent, stale |
Time since last deliberate interaction |
| Recent Engagement | recentEngagement |
cold, warming, hot |
Count of deliberate interactions in the last 10 seconds |
| Auction Attention | auctionAttention |
low, medium, high |
Whether the user is attentive right now |
| Page Momentum | pageMomentum |
arrival, in_reading_flow, post_scroll, fatigued |
Phase of the page visit lifecycle |
All 11 features are written into global ORTB2 fragments, available to every bidder:
Structured features at site.ext.data.msclarity:
{
"engagement": "high",
"dwell": "moderate",
"scroll": "deep",
"frustration": "none",
"interaction": "active",
"readingMode": "read",
"viewQuality": "high",
"activityRecency": "live",
"recentEngagement": "hot",
"auctionAttention": "high",
"pageMomentum": "in_reading_flow"
}
User segments at user.data:
[{
"name": "msclarity",
"segment": [
{ "id": "engagement_high" },
{ "id": "dwell_moderate" },
{ "id": "scroll_deep" },
{ "id": "frustration_none" },
{ "id": "interaction_active" },
{ "id": "readingMode_read" },
{ "id": "viewQuality_high" },
{ "id": "activityRecency_live" },
{ "id": "recentEngagement_hot" },
{ "id": "auctionAttention_high" },
{ "id": "pageMomentum_in_reading_flow" }
]
}]
Keywords at site.keywords:
msc_engagement=high,msc_dwell=moderate,msc_scroll=deep,msc_interaction=active,msc_readingMode=read,msc_viewQuality=high,msc_activityRecency=live,msc_recentEngagement=hot,msc_auctionAttention=high,msc_pageMomentum=in_reading_flow
The frustration keyword is omitted when its value is "none" to reduce noise.
The module persists the 7 durable features to localStorage (key: msc_rtd_signals) with a 30-minute TTL. On the first auction of a new page load, if all durable features are at baseline defaults, the module falls back to the cached snapshot. Transient snapshot features are always computed fresh.
The storage manager respects consent — if localStorage access is blocked by consent management, warm-start is silently skipped.
storageManager and respects TCF/GPP consent signals.params.injectClarity: false.projectId is not configured, the module silently disables itself.