skills-templates/cloudflare-zaraz/SKILL.md
Server-side tag management for third-party tools with edge execution, privacy controls, and near-zero performance impact
npx skillsauth add enuno/claude-command-and-control cloudflare-zarazInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Server-side tag management platform that loads third-party tools at Cloudflare's edge, eliminating client-side performance impact while providing privacy controls and consent management.
Cloudflare Zaraz offloads third-party tools (analytics, advertising pixels, chatbots, marketing automation) to the cloud, executing at the edge rather than in the browser. This architecture delivers near-zero performance impact while enhancing security and privacy.
When tools support automatic actions:
zaraz.track() Web APIzaraz.ecommerce() APIThe Zaraz Web API enables programmatic control from anywhere in the <body> tag.
Track custom events and user actions.
// Syntax
zaraz.track(eventName, [eventProperties])
// Basic event
zaraz.track("button_click")
// Event with properties
zaraz.track("purchase", {
value: 200,
currency: "USD",
product_id: "SKU-123"
})
// Async usage
await zaraz.track("signup_complete", { plan: "premium" })
Common Use Cases:
Accessing Properties in Triggers:
{{ client.value }}
{{ client.`product_id` }} // Use backticks for special characters
Store variables for use across all events without repetition.
// Syntax
zaraz.set(key, value, [options])
// Page scope (cleared on navigation)
zaraz.set("page_category", "blog", { scope: "page" })
// Session scope (persists during session)
zaraz.set("user_tier", "premium", { scope: "session" })
// Persist scope (localStorage, survives sessions) - DEFAULT
zaraz.set("user_id", "12345", { scope: "persist" })
zaraz.set("user_id", "12345") // Same as above
// Unset a variable
zaraz.set("user_id", undefined)
Scope Options:
| Scope | Persistence | Use Case |
|-------|-------------|----------|
| page | Current page only | Page-specific context |
| session | Browser session | User session data |
| persist | localStorage (default) | Cross-session identity |
Track e-commerce events with standardized data structure.
// Syntax
zaraz.ecommerce(eventName, eventProperties)
// Product viewed
zaraz.ecommerce("Product Viewed", {
product_id: "507f1f77",
sku: "G-32",
name: "Monopoly",
price: 18.99,
category: "Games"
})
// Add to cart
zaraz.ecommerce("Product Added", {
product_id: "507f1f77",
name: "Monopoly",
price: 18.99,
quantity: 1
})
// Order completed
zaraz.ecommerce("Order Completed", {
order_id: "50314b8e",
total: 27.50,
revenue: 25.00,
shipping: 3.00,
tax: 2.00,
currency: "USD",
products: [
{
product_id: "507f1f77",
name: "Monopoly",
price: 18.99,
quantity: 1
}
]
})
Supported Events (18 total):
Product Properties:
| Property | Description |
|----------|-------------|
| product_id | Unique identifier |
| sku | Stock keeping unit |
| name | Product name |
| brand | Brand name |
| category | Product category |
| variant | Product variant |
| price | Unit price |
| quantity | Number of items |
| coupon | Applied coupon |
| position | List position |
Order Properties:
| Property | Description |
|----------|-------------|
| order_id | Order identifier |
| checkout_id | Checkout identifier |
| total | Total amount |
| revenue | Revenue (excl. shipping/tax) |
| shipping | Shipping cost |
| tax | Tax amount |
| discount | Discount applied |
| currency | Currency code |
Compatible Tools:
For Single Page Applications, Zaraz automatically tracks virtual pageviews when URLs change (enable in Settings).
// Manual SPA pageview (advanced use)
zaraz.spaPageview()
Triggers define conditions for action execution.
Compare variables against match strings.
Variables Available:
Match Operations:
Monitor clicks using CSS selectors or XPath.
/* CSS Examples */
#submit-button /* ID selector */
.cta-button /* Class selector */
button[type="submit"] /* Attribute selector */
Parameters:
Track form submissions with optional validation.
/* Form selector */
#checkout-form
form[name="contact"]
Parameters:
Fire when elements become visible in viewport.
/* Visibility triggers */
#promo-banner
.video-player
Trigger at scroll thresholds.
100px /* Fixed pixel value */
50% /* Viewport percentage */
Execute after intervals.
Parameters:
Prevent actions from firing under specific conditions.
Firing Trigger: Pageview
Blocking Trigger: URL contains "/admin"
Key Points:
GDPR and ePrivacy Directive compliance through built-in CMP.
Purpose: Reason for loading a tool (e.g., "Analytics", "Advertising") Consent: User permission to store/access cookies
User preferences stored in first-party cookie:
{
"analytics": true,
"advertising": false,
"functional": true
}
// Wait for API ready
document.addEventListener("zarazConsentAPIReady", () => {
// Check specific purpose
const analyticsConsent = zaraz.consent.get("analytics")
// Get all consent statuses
const allConsent = zaraz.consent.getAll()
// Set consent for specific purposes
zaraz.consent.set({
analytics: true,
advertising: false
})
// Accept or reject all
zaraz.consent.setAll(true) // Accept all
zaraz.consent.setAll(false) // Reject all
// Show consent modal
zaraz.consent.modal = true
})
// Listen for consent changes
document.addEventListener("zarazConsentChoicesUpdated", () => {
console.log("User updated consent preferences")
})
// Send queued events after consent
zaraz.consent.sendQueuedEvents()
API Methods:
| Method | Description |
|--------|-------------|
| get(purposeId) | Get consent for specific purpose |
| set(preferences) | Update consent for purposes |
| getAll() | Get all consent statuses |
| setAll(status) | Set all purposes |
| getAllCheckboxes() | Get checkbox states |
| setCheckboxes(states) | Update checkboxes |
| setAllCheckboxes(state) | Set all checkboxes |
| sendQueuedEvents() | Send blocked events after consent |
Properties:
| Property | Description |
|----------|-------------|
| modal | Show/hide consent modal |
| purposes | Read-only purpose definitions |
| APIReady | Boolean API availability |
document.addEventListener("zarazConsentAPIReady", () => {
// Show modal only for EU visitors
if (zaraz.consent.purposes.analytics.region === "EU") {
zaraz.consent.modal = true
} else {
zaraz.consent.setAll(true)
}
})
| Property | Description | |----------|-------------| | Event Name | Name from zaraz.track() | | Track Property | Values from eventProperties or zaraz.set() |
| Property | Description | |----------|-------------| | Page encoding | Document character encoding | | Page referrer | Referring URL | | Page title | Document title | | Query param | Specific URL parameter | | URL (various) | host, hostname, origin, pathname, port, protocol |
| Property | Description | |----------|-------------| | Browser engine/name/version | Browser details | | Device type | Desktop, mobile, tablet | | Device CPU | Processor architecture | | Language | Browser language | | Resolution | Screen dimensions | | Viewport | Browser viewport size | | OS name/version | Operating system | | User-agent | Full UA string | | IP address | Visitor IP |
| Property | Description | |----------|-------------| | City | Visitor city | | Continent | Geographic continent | | Country | Country code | | EU | EU membership (1/0) | | Region | Region name | | Region code | ISO 3166-2 code | | Timezone | Visitor timezone |
| Property | Description | |----------|-------------| | Random number | Unique per request | | Timestamp (ms/s) | Unix timestamp | | Cookie | Browser cookie value |
Migrate from Google Tag Manager without code changes.
// Existing GTM code
dataLayer.push({
event: 'purchase',
price: '24',
currency: 'USD'
})
// Automatically converted to
zaraz.track('purchase', { price: '24', currency: 'USD' })
Note: E-commerce mapping not supported via dataLayer. Use zaraz.ecommerce() instead.
Enrich event data using Cloudflare Workers.
export default {
async fetch(request) {
const { system, client } = await request.json()
// Add weather data
const weather = await fetch('https://api.weather.com/...')
client.weather = await weather.json()
// Redact email addresses
for (const key in client) {
if (typeof client[key] === 'string' && client[key].includes('@')) {
client[key] = '[REDACTED]'
}
}
return new Response(JSON.stringify({ system, client }))
}
}
| Setting | Description | |---------|-------------| | Real-time | Changes publish immediately | | Preview & Publish | Test before deployment |
| Setting | Description | |---------|-------------| | Debug Key | Enable Debug Mode | | E-commerce tracking | Enable zaraz.ecommerce() |
| Setting | Description | |---------|-------------| | Data layer mode | GTM dataLayer.push() support | | SPA support | Virtual pageviews on URL change |
| Setting | Description | |---------|-------------| | Remove query params | Strip URL parameters | | Trim IP addresses | Remove before sending to tools | | Hide user-agent | Sanitize sensitive details | | Hide referrer | Hide external referrers | | Cookie domain | Custom cookie domain |
| Setting | Description | |---------|-------------| | Auto-inject | Load Zaraz automatically | | Iframe injection | Inject into iframes |
| Setting | Description | |---------|-------------| | Custom paths | Custom script pathnames |
| Setting | Description | |---------|-------------| | Bot threshold | Block suspected bot traffic | | Context Enricher | Worker for data enrichment | | Logpush | Export logs (Enterprise) |
| Metric | Description | |--------|-------------| | Loads | Zaraz script loads | | Events | Tracked events (pageview, custom, ecommerce) | | Triggers | Trigger activations | | Actions | Action executions | | Server-side requests | HTTP status codes from third-party tools |
// Check if Zaraz is loaded
if (typeof zaraz !== 'undefined') {
console.log('Zaraz loaded successfully')
}
// Enable Debug Mode in console
// Access real-time event monitoring
| Issue | Solution |
|-------|----------|
| zaraz is not defined | Verify domain is proxied, Auto Injection enabled |
| Browser extension can't detect tools | Use Debug Mode (server-side execution) |
| E-commerce returns undefined | Enable E-commerce tracking in Settings |
| Demographics missing in GA | Use "Anonymize IP" instead of "Hide IP" |
import { useEffect } from 'react'
function ProductPage({ product }) {
useEffect(() => {
// Track product view
if (typeof zaraz !== 'undefined') {
zaraz.ecommerce('Product Viewed', {
product_id: product.id,
name: product.name,
price: product.price,
category: product.category
})
}
}, [product])
const handleAddToCart = () => {
if (typeof zaraz !== 'undefined') {
zaraz.ecommerce('Product Added', {
product_id: product.id,
name: product.name,
price: product.price,
quantity: 1
})
}
// Add to cart logic
}
return (
<div>
<h1>{product.name}</h1>
<button onClick={handleAddToCart}>Add to Cart</button>
</div>
)
}
// components/ConsentBanner.jsx
import { useEffect, useState } from 'react'
export function ConsentBanner() {
const [showBanner, setShowBanner] = useState(false)
useEffect(() => {
const handleReady = () => {
const allConsent = zaraz.consent.getAll()
if (Object.keys(allConsent).length === 0) {
setShowBanner(true)
}
}
document.addEventListener('zarazConsentAPIReady', handleReady)
return () => document.removeEventListener('zarazConsentAPIReady', handleReady)
}, [])
const acceptAll = () => {
zaraz.consent.setAll(true)
setShowBanner(false)
}
const rejectAll = () => {
zaraz.consent.setAll(false)
setShowBanner(false)
}
if (!showBanner) return null
return (
<div className="consent-banner">
<p>We use cookies to improve your experience.</p>
<button onClick={acceptAll}>Accept All</button>
<button onClick={rejectAll}>Reject All</button>
<button onClick={() => zaraz.consent.modal = true}>
Customize
</button>
</div>
)
}
<template>
<button @click="trackClick">{{ label }}</button>
</template>
<script setup>
import { onMounted } from 'vue'
const props = defineProps({
label: String,
eventName: String,
eventProps: Object
})
onMounted(() => {
if (typeof zaraz !== 'undefined') {
zaraz.set('component_loaded', props.label, { scope: 'page' })
}
})
function trackClick() {
if (typeof zaraz !== 'undefined') {
zaraz.track(props.eventName, props.eventProps)
}
}
</script>
// Step 1: Checkout started
zaraz.ecommerce('Checkout Started', {
checkout_id: 'CHK-123',
value: 50.00,
currency: 'USD',
products: cartItems
})
// Step 2: Shipping info
zaraz.ecommerce('Shipping Info Entered', {
checkout_id: 'CHK-123',
shipping_method: 'standard'
})
// Step 3: Payment info
zaraz.ecommerce('Payment Info Entered', {
checkout_id: 'CHK-123',
payment_method: 'credit_card'
})
// Step 4: Order completed
zaraz.ecommerce('Order Completed', {
order_id: 'ORD-456',
checkout_id: 'CHK-123',
total: 53.00,
revenue: 50.00,
shipping: 3.00,
tax: 0,
currency: 'USD',
products: cartItems
})
tools
MemPalace local-first AI memory system. Use when setting up persistent memory for Claude Code sessions, mining project files or conversation transcripts, querying past context, configuring MCP tools, managing the knowledge graph, or troubleshooting palace operations.
tools
LangSmith Python SDK — trace, evaluate, and monitor LLM applications. Covers @traceable decorator, trace context manager, Client API, evaluate() / aevaluate(), comparative evaluation, custom evaluators, dataset management, prompt caching, ASGI middleware, and pytest plugin.
development
LangGraph (Python) — build stateful, controllable agent graphs with checkpointing, streaming, persistence, interrupts, fault tolerance, and durable execution. Covers both Graph API (StateGraph) and Functional API (@entrypoint/@task).
development
LangGraph Graph API (Python) — build explicit DAG agent workflows with StateGraph, typed state, nodes, edges, Command routing, Send fan-out, checkpointers, interrupts, and streaming. Use when you need explicit control flow and graph topology.