Chrome Extension — Full Walkthrough
This walkthrough takes you through a complete scenario from start to finish. You will:
- Map an e-commerce domain to a 10x.in handle.
- Create two experiments: an exit-intent popup and a scroll-triggered banner.
- Install the Chrome extension and see both experiments fire.
Scenario
Acme Store (acmestore.com) wants to:
- Show a 10% discount popup when visitors try to leave the page.
- Show a free shipping banner after visitors scroll past 50% of the page.
The marketer has a 10x.in handle acmestore and will map the subdomain go.acmestore.com.
Part 1: Backend setup (Marketer)
Set up your environment:
export OWNER_JWT="eyJ_owner_jwt_here"
export TOKEN="patv1_your_token_here" # or a CREATOR JWT for chain-rule writes
export API="https://api.10x.in"
export HANDLE="acmestore"
1.1 Register the domain
curl -X POST "$API/v2/account/domains" \
-H "Authorization: Bearer $OWNER_JWT" \
-H "Content-Type: application/json" \
-d '{
"domain": "go.acmestore.com",
"sourceType": "BYOD_HOSTNAME",
"defaultHandle": "acmestore"
}'
Expected response:
{
"domain": {
"domain": "go.acmestore.com",
"status": "PENDING_DELEGATION",
"statusReason": "awaiting_nameserver_delegation"
},
"verification": {
"txtName": "_ls-verify.go.acmestore.com",
"txtValue": "lsv1...."
}
}
1.2 Configure DNS
Capture verification.txtName and verification.txtValue, then run reconcile once so 10x returns the delegated nameservers for your domain:
curl -X POST "$API/v2/account/domains/go.acmestore.com/reconcile" \
-H "Authorization: Bearer $OWNER_JWT" \
-H "Content-Type: application/json" \
-d '{}'
Then fetch the domain record and use the returned values in DNS:
curl "$API/v2/account/domains/go.acmestore.com" \
-H "Authorization: Bearer $OWNER_JWT"
Apply the current domain-management flow:
| Record type | Where | Value source |
|---|---|---|
NS | Registrar for go.acmestore.com or apex delegation point | domain.nameservers[] from the API |
TXT | Delegated zone | verification.txtName + verification.txtValue from create response |
| Traffic record | Delegated zone | Exact edge target shown in Domain Management / API details |
Warning
Do not hardcode domains.10x.in for this flow. The current custom-domain contract uses the nameservers and edge target returned for your domain after reconcile.
1.3 Verify and reconcile
After DNS propagation, trigger reconciliation again:
curl -X POST "$API/v2/account/domains/go.acmestore.com/reconcile" \
-H "Authorization: Bearer $OWNER_JWT" \
-H "Content-Type: application/json" \
-d '{}'
Check the status:
curl "$API/v2/account/domains/go.acmestore.com" \
-H "Authorization: Bearer $OWNER_JWT"
Look for "status": "ACTIVE" in the response. If it still says PENDING_DELEGATION, PENDING_CERT, or PENDING_EDGE_DEPLOY, follow statusReason, wait for propagation, and reconcile again.
1.4 Confirm the public lookup works
This is the endpoint the Chrome extension calls:
curl "$API/v2/public/domain-lookup?domain=go.acmestore.com"
{
"handle": "acmestore",
"pathRules": [],
"status": "ACTIVE"
}
Part 2: Create experiments
2.1 Exit-intent popup: "10% off if you stay"
This rule fires when the visitor moves their mouse above the browser viewport (the universal "about to close the tab" gesture).
curl -X PUT "$API/v2/handles/$HANDLE/chain-rules/exit-discount" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ruleId": "exit-discount",
"enabled": true,
"priority": 10,
"triggerEvent": "exit_intent",
"when": {},
"chainConditions": { "require": [], "exclude": [] },
"action": {
"type": "show_popup",
"template": "<div id=\"tenx-exit-overlay\" style=\"position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.6);display:flex;align-items:center;justify-content:center;z-index:99999;font-family:-apple-system,BlinkMacSystemFont,sans-serif\"><div style=\"background:white;padding:48px;border-radius:16px;text-align:center;max-width:420px;box-shadow:0 24px 48px rgba(0,0,0,0.2)\"><div style=\"font-size:48px;margin-bottom:16px\">🎁</div><h2 style=\"margin:0 0 8px;font-size:24px;color:#111\">Wait — take 10% off!</h2><p style=\"color:#666;margin:0 0 24px;font-size:15px;line-height:1.5\">Use code <strong>EXIT10</strong> at checkout.<br/>This offer disappears when you leave.</p><a href=\"/checkout?coupon=EXIT10\" style=\"background:#0B6B3A;color:white;padding:14px 32px;border-radius:8px;text-decoration:none;display:inline-block;font-weight:600;font-size:15px\">Claim My Discount</a><p style=\"margin:16px 0 0;font-size:13px;color:#999;cursor:pointer\" onclick=\"document.getElementById('tenx-exit-overlay').remove()\">No thanks, I'll pay full price</p></div></div>",
"vars": { "coupon": "EXIT10", "discount": "10%" }
}
}'
2.2 Scroll banner: "Free shipping over $50"
This rule fires when the visitor scrolls past 50% of the page, indicating engagement.
curl -X PUT "$API/v2/handles/$HANDLE/chain-rules/scroll-shipping" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ruleId": "scroll-shipping",
"enabled": true,
"priority": 20,
"triggerEvent": "scroll_50",
"when": {},
"chainConditions": { "require": [], "exclude": [] },
"action": {
"type": "show_banner",
"template": "<div id=\"tenx-scroll-banner\" style=\"position:fixed;bottom:0;left:0;width:100%;background:#0B6B3A;color:white;padding:14px 20px;text-align:center;font-family:-apple-system,BlinkMacSystemFont,sans-serif;font-size:14px;z-index:99998;display:flex;align-items:center;justify-content:center;gap:12px;box-shadow:0 -2px 12px rgba(0,0,0,0.15)\"><span>🚚 Free shipping on orders over $50!</span><a href=\"/shop\" style=\"background:white;color:#0B6B3A;padding:6px 16px;border-radius:6px;text-decoration:none;font-weight:600;font-size:13px\">Shop Now</a><span style=\"cursor:pointer;margin-left:8px;opacity:0.7\" onclick=\"document.getElementById('tenx-scroll-banner').remove()\">✕</span></div>"
}
}'
2.3 Verify experiments are active
Prefetch all decisions to confirm both rules are matched:
curl -X POST "$API/v2/public/chain/prefetch" \
-H "Content-Type: application/json" \
-d '{
"handle": "acmestore",
"triggerEvents": ["page_load", "exit_intent", "scroll_50", "scroll_75", "idle_30s"]
}'
Expected response (abbreviated):
{
"decisions": {
"page_load": { "matched": false },
"exit_intent": {
"matched": true,
"ruleId": "exit-discount",
"action": { "type": "show_popup", "template": "..." }
},
"scroll_50": {
"matched": true,
"ruleId": "scroll-shipping",
"action": { "type": "show_banner", "template": "..." }
},
"scroll_75": { "matched": false },
"idle_30s": { "matched": false }
}
}
Both exit_intent and scroll_50 show "matched": true.
Part 3: Install and test the extension
3.1 Build and load the extension
cd chrome-extension
npm install
npm run build
Open chrome://extensions, enable Developer Mode, click Load unpacked, select chrome-extension/dist/.
3.2 Log in
Click the 10x.in icon in the toolbar. Either:
- Email Login with your 10x.in credentials, or
- PAT Token — paste your
patv1_...token
3.3 Visit your domain
Navigate to https://go.acmestore.com (or any page on that domain).
What you should see:
- The extension badge turns green with the number 2 (two active experiments).
- Click the extension icon — the popup shows
acmestorehandle and "2 experiments running."
3.4 Trigger the scroll banner
Scroll down the page past the 50% mark.
Result: A green banner slides in at the bottom of the page: "Free shipping on orders over $50! Shop Now"
3.5 Trigger the exit-intent popup
Move your mouse cursor to the top of the browser window (above the page content, toward the tab bar).
Result: A centered popup overlay appears: "Wait — take 10% off!" with a "Claim My Discount" button.
Part 4: Extending the setup
Add a personalization rule for mobile visitors
Show a different CTA for mobile visitors:
curl -X PUT "$API/v2/handles/$HANDLE/personalization-rules/mobile-cta" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ruleId": "mobile-cta",
"enabled": true,
"priority": 10,
"when": {
"deviceIn": ["MOBILE"]
},
"variant": {
"id": "mobile-variant",
"cta": "Tap to Shop — Mobile Exclusive",
"title": "Acme Store — Mobile Deals"
}
}'
Add a signal-based chain rule
Show a popup only if the visitor has viewed 3+ product pages in this session. This requires signals to be written first (the tracking SDK does this automatically when injected by the extension):
curl -X PUT "$API/v2/handles/$HANDLE/chain-rules/engaged-visitor-offer" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ruleId": "engaged-visitor-offer",
"enabled": true,
"priority": 5,
"triggerEvent": "idle_30s",
"when": {},
"chainConditions": {
"require": [
{ "signalKey": "page_view", "operator": "count_gte", "signalValue": "3" }
],
"exclude": [],
"minChainDepth": 3
},
"action": {
"type": "show_popup",
"template": "<div style=\"position:fixed;bottom:20px;right:20px;background:white;padding:24px;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.15);max-width:320px;z-index:99999;font-family:sans-serif\"><h3 style=\"margin:0 0 8px\">You seem interested!</h3><p style=\"color:#666;margin:0 0 16px;font-size:14px\">Chat with us about your needs.</p><a href=\"/contact\" style=\"background:#0B6B3A;color:white;padding:10px 20px;border-radius:6px;text-decoration:none;font-size:14px\">Start a Chat</a></div>"
}
}'
This rule only fires after the visitor has accumulated 3+ page_view signals in their session and then goes idle for 30 seconds.
Verification checklist
- [ ]
go.acmestore.comreturnsACTIVEfrom domain-lookup - [ ] Chain prefetch returns 2 matched rules (
exit-discount,scroll-shipping) - [ ] Extension badge shows green with "2" on
go.acmestore.com - [ ] Scrolling past 50% triggers the shipping banner
- [ ] Moving mouse to top of viewport triggers the discount popup
- [ ] Popup "No thanks" link dismisses the overlay
- [ ] Banner "✕" button dismisses the banner
Related guides
- Chrome Extension — User Guide — Installation and usage
- Chrome Extension — Marketer Setup — Configuration reference
- Chain Signals and Prefetch — Signal model and advanced chain rules
- Smart Link Personalization — Personalization deep dive
- Custom Domains — Full domain mapping reference