name: cloudflare-zaraz description: Server-side tag management for third-party tools with edge execution, privacy controls, and near-zero performance impact version: 1.0.0 tags: [cloudflare, zaraz, tag-management, analytics, privacy, edge, performance, consent]
Cloudflare Zaraz
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.
Overview
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.
Key Benefits
- Performance: Load multiple tools with minimal client impact
- Privacy: Built-in IP anonymization, referrer hiding, user-agent trimming
- Security: Server-side execution reduces attack surface
- Consent: Integrated Consent Management Platform (CMP)
- Simplicity: No code changes needed for most integrations
Getting Started
Prerequisites
- Website proxied through Cloudflare (recommended)
- At least one tool configured in Zaraz
- Auto-inject script enabled (default)
Adding Third-Party Tools
- Navigate to Zaraz > Tools configuration in Cloudflare dashboard
- Select Third-party tools > Add new tool
- Browse the tools catalog and select your tool
- Configure tool-specific settings
- Set up actions with firing triggers
- Save configuration
Automatic Action Types
When tools support automatic actions:
- Pageviews: Track all page loads automatically
- Events: Monitor via
zaraz.track()Web API - E-Commerce: Process transactions via
zaraz.ecommerce()API
Web API
The Zaraz Web API enables programmatic control from anywhere in the <body> tag.
zaraz.track()
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:
- User actions (sign-ups, button clicks, purchases)
- Page interactions (widget loads, element impressions)
- Form submissions
Accessing Properties in Triggers:
{{ client.value }}
{{ client.`product_id` }} // Use backticks for special characters
zaraz.set()
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 |
zaraz.ecommerce()
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 List Viewed, Products Searched
- Product Clicked, Product Viewed, Product Added, Product Removed
- Product Added to Wishlist
- Cart Viewed
- Checkout Started, Checkout Step Viewed, Checkout Step Completed
- Payment Info Entered, Shipping Info Entered
- Order Completed, Order Updated, Order Refunded, Order Cancelled
- Clicked Promotion, Viewed Promotion
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:
- Google Analytics 4
- Google Analytics (Universal)
- Facebook Pixel
- Bing
- Pinterest Conversions API
- TikTok
- Amplitude
- Branch
SPA Support
For Single Page Applications, Zaraz automatically tracks virtual pageviews when URLs change (enable in Settings).
// Manual SPA pageview (advanced use)
zaraz.spaPageview()
Triggers
Triggers define conditions for action execution.
Match Rule
Compare variables against match strings.
Variables Available:
- Event Name
- URL components (pathname, host, query)
- Cookies
- Device Properties
- Page Properties
Match Operations:
- Equals / Does not equal
- Contains / Does not contain
- Starts with / Ends with
- Matches regex / Does not match regex
- Greater than / Less than
Click Listener
Monitor clicks using CSS selectors or XPath.
/* CSS Examples */
#submit-button /* ID selector */
.cta-button /* Class selector */
button[type="submit"] /* Attribute selector */
Parameters:
- Selector: CSS selector or XPath expression
- Wait for actions: Delay navigation (ms) to ensure requests complete
Form Submission
Track form submissions with optional validation.
/* Form selector */
#checkout-form
form[name="contact"]
Parameters:
- Selector: CSS selector for form
- Validate: Only trigger on valid submissions
Element Visibility
Fire when elements become visible in viewport.
/* Visibility triggers */
#promo-banner
.video-player
Scroll Depth
Trigger at scroll thresholds.
100px /* Fixed pixel value */
50% /* Viewport percentage */
Timer
Execute after intervals.
Parameters:
- Interval: Milliseconds between executions
- Limit: Maximum executions (0 = unlimited)
Blocking Triggers
Prevent actions from firing under specific conditions.
Firing Trigger: Pageview
Blocking Trigger: URL contains "/admin"
Key Points:
- Inverse of firing triggers
- Zaraz script still loads
- Must apply to each action individually
Consent Management
GDPR and ePrivacy Directive compliance through built-in CMP.
Key Concepts
Purpose: Reason for loading a tool (e.g., "Analytics", "Advertising") Consent: User permission to store/access cookies
Consent Storage
User preferences stored in first-party cookie:
{
"analytics": true,
"advertising": false,
"functional": true
}
Consent API
// 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 |
Region-Based Consent
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)
}
})
Properties Reference
Event Properties
| Property | Description |
|---|---|
| Event Name | Name from zaraz.track() |
| Track Property | Values from eventProperties or zaraz.set() |
Page Properties
| 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 |
Device Properties
| 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 |
Location Properties
| 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 |
Miscellaneous
| Property | Description |
|---|---|
| Random number | Unique per request |
| Timestamp (ms/s) | Unix timestamp |
| Cookie | Browser cookie value |
Data Layer Compatibility
Migrate from Google Tag Manager without code changes.
Enable Compatibility Mode
- Navigate to Zaraz > Settings
- Enable Data layer compatibility mode
How It Works
// 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.
Context Enricher
Enrich event data using Cloudflare Workers.
Basic Structure
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 }))
}
}
Setup
- Create Worker in Cloudflare dashboard or via Wrangler
- Navigate to Zaraz > Settings
- Select your Worker as Context Enricher
Settings Reference
Workflow
| Setting | Description |
|---|---|
| Real-time | Changes publish immediately |
| Preview & Publish | Test before deployment |
Web API
| Setting | Description |
|---|---|
| Debug Key | Enable Debug Mode |
| E-commerce tracking | Enable zaraz.ecommerce() |
Compatibility
| Setting | Description |
|---|---|
| Data layer mode | GTM dataLayer.push() support |
| SPA support | Virtual pageviews on URL change |
Privacy
| 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 |
Injection
| Setting | Description |
|---|---|
| Auto-inject | Load Zaraz automatically |
| Iframe injection | Inject into iframes |
Endpoints
| Setting | Description |
|---|---|
| Custom paths | Custom script pathnames |
Advanced
| Setting | Description |
|---|---|
| Bot threshold | Block suspected bot traffic |
| Context Enricher | Worker for data enrichment |
| Logpush | Export logs (Enterprise) |
Supported Tools
Analytics
- Amplitude
- Google Analytics (Universal)
- Google Analytics 4
- Mixpanel
- Segment
- Snowplow
- Pod Sights
Advertising
- Bing
- Facebook Pixel
- Floodlight
- Google Ads
- LinkedIn Insight
- Outbrain
- Pinterest / Pinterest Conversions API
- Quora
- Snapchat
- Taboola
- Tatari
- TikTok
- Twitter Pixel
Marketing
- Branch
- HubSpot
- Impact Radius
Recruiting
- Indeed
- iHire
- Upward
- ZipRecruiter
Custom Integrations
- Custom HTML
- Custom Image
- HTTP Request
Monitoring
Metrics Available
| 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 |
Debug Mode
- Set Debug Key in Zaraz Settings
- Access via browser console
- View real-time event flow
Best Practices
Performance
- Use native integrations over Custom HTML
- Enable SPA support for single-page applications
- Use blocking triggers to prevent unnecessary actions
- Minimize Custom HTML - runs client-side
Privacy
- Enable IP trimming for GDPR compliance
- Configure consent purposes before enabling tools
- Use Context Enricher to redact sensitive data
- Hide referrers for cross-domain tracking protection
Migration from GTM
- Don't use GTM with Zaraz - loses optimization benefits
- Enable data layer compatibility for gradual migration
- Convert to native integrations over time
- Use zaraz.ecommerce() instead of dataLayer for e-commerce
Debugging
// Check if Zaraz is loaded
if (typeof zaraz !== 'undefined') {
console.log('Zaraz loaded successfully')
}
// Enable Debug Mode in console
// Access real-time event monitoring
Common Issues
| 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" |
Integration Examples
React E-commerce
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>
)
}
Next.js with Consent
// 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>
)
}
Vue.js Event Tracking
<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>
Checkout Flow
// 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
})