Skip to content

Commit 91b2d67

Browse files
committed
feat: add Plausible Analytics setup with Cloudflare Worker proxy and tracking functions
- Introduced new documentation for setting up Plausible with a Cloudflare Worker proxy - Added a new worker script to proxy Plausible requests and avoid ad-blockers - Updated demo app to initialize Plausible with custom API host and tracking options - Created analytics utility functions for initializing and tracking events with optional properties and revenue - Modified layout to include Plausible initialization on mount - Updated package dependencies to include @plausible-analytics/tracker - Enhanced tracking capabilities with support for custom events and revenue data - Improved configuration flexibility and obfuscation to prevent detection and blocking - Overall, integrated first-party Plausible tracking via proxy for more reliable analytics
1 parent e673bd3 commit 91b2d67

File tree

6 files changed

+390
-0
lines changed

6 files changed

+390
-0
lines changed

apps/demo/PLAUSIBLE_SETUP.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Plausible Analytics Setup Guide
2+
3+
This guide walks you through setting up Plausible Analytics with a Cloudflare Worker proxy for the pgflow demo app.
4+
5+
## Overview
6+
7+
The setup consists of three parts:
8+
1. Plausible dashboard configuration
9+
2. Cloudflare Worker proxy deployment
10+
3. SvelteKit app configuration
11+
12+
## Part 1: Plausible Dashboard Setup
13+
14+
1. **Sign up or log in** to [Plausible](https://plausible.io)
15+
16+
2. **Add your website**
17+
- Click "Add a website"
18+
- Enter your domain (e.g., `demo.pgflow.dev`)
19+
- Click "Add site"
20+
21+
3. **Get your script URL**
22+
- Go to Site Settings > General > Site Installation
23+
- Find your unique script URL - it will look like:
24+
```
25+
https://plausible.io/js/pa-XXXXX.js
26+
```
27+
- **Save this URL** - you'll need it for the Cloudflare Worker
28+
29+
## Part 2: Cloudflare Worker Setup
30+
31+
### Step 1: Create the Worker
32+
33+
1. Go to your [Cloudflare Dashboard](https://dash.cloudflare.com)
34+
2. Navigate to "Workers & Pages" in the sidebar
35+
3. Click "Create" > "Create Worker"
36+
4. Give it a name (avoid words like 'analytics', 'tracking', 'stats')
37+
- Good examples: `proxy-service`, `data-relay`, `metrics-hub`
38+
5. Click "Deploy"
39+
40+
### Step 2: Configure the Worker
41+
42+
1. Click "Edit Code"
43+
2. Delete the default code
44+
3. Copy the code from `cloudflare-worker-plausible-proxy.js`
45+
4. **Update the configuration** at the top of the file:
46+
```javascript
47+
// Replace with your Plausible script URL from Part 1
48+
const ProxyScript = 'https://plausible.io/js/pa-XXXXX.js';
49+
50+
// Customize these paths (avoid obvious names)
51+
const ScriptName = '/metrics/script.js'; // Change to something unique
52+
const Endpoint = '/metrics/event'; // Should match folder above
53+
```
54+
5. Click "Save and Deploy"
55+
56+
### Step 3: Test the Worker
57+
58+
1. Your worker will be available at:
59+
```
60+
https://your-worker-name.your-account.workers.dev
61+
```
62+
63+
2. Test if the script is accessible:
64+
```
65+
https://your-worker-name.your-account.workers.dev/metrics/script.js
66+
```
67+
You should see JavaScript code (the Plausible script)
68+
69+
### Step 4 (Optional): Add a Custom Route
70+
71+
If your site is on Cloudflare CDN, you can run the proxy as a subdirectory:
72+
73+
1. In the Worker settings, go to "Triggers" > "Routes"
74+
2. Click "Add route"
75+
3. Configure:
76+
- Route: `*yourdomain.com/analytics/*` (change "analytics" to something else)
77+
- Zone: Select your domain
78+
4. Click "Save"
79+
80+
Now your proxy will be available at:
81+
```
82+
https://yourdomain.com/analytics/metrics/script.js
83+
https://yourdomain.com/analytics/metrics/event
84+
```
85+
86+
## Part 3: SvelteKit App Configuration
87+
88+
### Update the Layout File
89+
90+
Open `apps/demo/src/routes/+layout.svelte` and update the TODO section:
91+
92+
```typescript
93+
onMount(() => {
94+
initPlausible({
95+
domain: 'demo.pgflow.dev', // Your actual domain
96+
apiHost: 'https://your-worker.workers.dev/metrics', // Your proxy URL
97+
trackLocalhost: false // Set to true for testing locally
98+
});
99+
});
100+
```
101+
102+
**Configuration options:**
103+
104+
- **Without custom route** (worker URL):
105+
```typescript
106+
apiHost: 'https://your-worker-name.your-account.workers.dev/metrics'
107+
```
108+
109+
- **With custom route** (subdirectory):
110+
```typescript
111+
apiHost: '/analytics/metrics' // Relative path works!
112+
```
113+
114+
## Part 4: Track Custom Events
115+
116+
Use the `track()` function anywhere in your SvelteKit app:
117+
118+
```typescript
119+
import { track } from '$lib/analytics';
120+
121+
// Simple event
122+
track('button_clicked');
123+
124+
// Event with properties
125+
track('signup', {
126+
tier: 'pro',
127+
plan: 'monthly',
128+
source: 'landing_page'
129+
});
130+
131+
// Event with revenue tracking
132+
track('purchase', {
133+
product: 'pro-plan',
134+
quantity: 1
135+
}, {
136+
amount: 29.99,
137+
currency: 'USD'
138+
});
139+
```
140+
141+
### Common Event Examples
142+
143+
```typescript
144+
// User signup
145+
track('signup', { method: 'email' });
146+
147+
// Feature usage
148+
track('flow_created', { flow_type: 'data_pipeline' });
149+
150+
// Form submission
151+
track('contact_form', { page: 'pricing' });
152+
153+
// Download tracking (already automatic with fileDownloads: true)
154+
// But you can track custom downloads:
155+
track('documentation_download', { doc_type: 'api_reference' });
156+
```
157+
158+
## Part 5: Verify Installation
159+
160+
1. **Start your dev server**:
161+
```bash
162+
pnpm nx dev demo
163+
```
164+
165+
2. **Open your browser console** and look for:
166+
```
167+
[Plausible] Initialized successfully
168+
```
169+
170+
3. **Check Plausible dashboard**:
171+
- Go to your Plausible dashboard
172+
- You should see pageviews appearing in real-time
173+
- Note: It may take a few seconds for events to appear
174+
175+
4. **Test custom events**:
176+
```typescript
177+
// In browser console or your code
178+
track('test_event', { test: true });
179+
```
180+
- Check Plausible dashboard > Custom Events to see it
181+
182+
## Troubleshooting
183+
184+
### Events not showing up
185+
186+
1. Check browser console for errors
187+
2. Verify the proxy worker is accessible
188+
3. Check that `domain` in config matches your Plausible site exactly
189+
4. Make sure you're not on localhost (unless `trackLocalhost: true`)
190+
191+
### Worker not accessible
192+
193+
1. Verify the worker is deployed (check Cloudflare dashboard)
194+
2. Check the worker logs for errors
195+
3. Test the script URL directly in your browser
196+
197+
### Ad blocker blocking requests
198+
199+
1. Make sure you're using the proxy (not direct Plausible URLs)
200+
2. Avoid obvious path names in your worker configuration
201+
3. Use a custom route on your own domain
202+
203+
## Production Checklist
204+
205+
- [ ] Updated `ProxyScript` in worker with your Plausible script URL
206+
- [ ] Customized `ScriptName` and `Endpoint` to avoid detection
207+
- [ ] Deployed Cloudflare Worker successfully
208+
- [ ] Tested worker script is accessible
209+
- [ ] Updated `domain` in `+layout.svelte` with production domain
210+
- [ ] Updated `apiHost` in `+layout.svelte` with worker URL
211+
- [ ] Set `trackLocalhost: false` for production
212+
- [ ] Verified events appear in Plausible dashboard
213+
- [ ] Tested custom event tracking
214+
215+
## Additional Resources
216+
217+
- [Plausible Documentation](https://plausible.io/docs)
218+
- [Plausible NPM Package](https://www.npmjs.com/package/@plausible-analytics/tracker)
219+
- [Cloudflare Workers Documentation](https://developers.cloudflare.com/workers/)
220+
- [Custom Events Guide](https://plausible.io/docs/custom-event-goals)
221+
- [Revenue Tracking Guide](https://plausible.io/docs/ecommerce-revenue-tracking)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Cloudflare Worker for Plausible Analytics Proxy
3+
*
4+
* IMPORTANT: You MUST update the ProxyScript variable below with your
5+
* actual Plausible script URL from your dashboard before deploying!
6+
*/
7+
8+
// CONFIGURATION - UPDATE THIS VALUE!
9+
// Get this from your Plausible dashboard (Site Settings > Site Installation)
10+
// It will look like: https://plausible.io/js/script.js (or pa-XXXXX.js for custom domains)
11+
const ProxyScript = 'https://plausible.io/js/script.js'; // ← UPDATE THIS!
12+
13+
// Customize these paths to avoid ad-blocker detection
14+
const ScriptName = '/stats/script.js';
15+
const Endpoint = '/stats/event';
16+
17+
// Internal logic - do not edit below
18+
const ScriptWithoutExtension = ScriptName.replace('.js', '');
19+
20+
addEventListener('fetch', (event) => {
21+
event.passThroughOnException();
22+
event.respondWith(handleRequest(event));
23+
});
24+
25+
async function handleRequest(event) {
26+
const pathname = new URL(event.request.url).pathname;
27+
const [baseUri, ...extensions] = pathname.split('.');
28+
29+
if (baseUri.endsWith(ScriptWithoutExtension)) {
30+
return getScript(event, extensions);
31+
} else if (pathname.endsWith(Endpoint)) {
32+
return postData(event);
33+
}
34+
35+
return new Response(null, { status: 404 });
36+
}
37+
38+
async function getScript(event, extensions) {
39+
let response = await caches.default.match(event.request);
40+
if (!response) {
41+
response = await fetch(ProxyScript);
42+
event.waitUntil(caches.default.put(event.request, response.clone()));
43+
}
44+
return response;
45+
}
46+
47+
async function postData(event) {
48+
const request = new Request(event.request);
49+
request.headers.delete('cookie');
50+
return await fetch('https://plausible.io/api/event', request);
51+
}

apps/demo/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"dependencies": {
4848
"@pgflow/client": "workspace:*",
4949
"@pgflow/dsl": "workspace:*",
50+
"@plausible-analytics/tracker": "^0.4.4",
5051
"@supabase/supabase-js": "^2.78.0",
5152
"@xyflow/svelte": "^1.4.1",
5253
"shiki": "^3.14.0"

apps/demo/src/lib/analytics.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { init, track as trackEvent } from '@plausible-analytics/tracker';
2+
import { browser } from '$app/environment';
3+
4+
interface PlausibleConfig {
5+
domain: string;
6+
apiHost?: string;
7+
trackLocalhost?: boolean;
8+
}
9+
10+
let initialized = false;
11+
12+
/**
13+
* Initialize Plausible analytics tracking.
14+
* Should be called once when the app loads.
15+
*
16+
* @param config - Configuration options for Plausible
17+
* @param config.domain - Your site's domain (e.g., 'demo.pgflow.dev')
18+
* @param config.apiHost - Optional custom API endpoint (for proxy setup)
19+
* @param config.trackLocalhost - Whether to track events on localhost (default: false)
20+
*/
21+
export function initPlausible(config: PlausibleConfig): void {
22+
// Only run in browser environment
23+
if (!browser) {
24+
return;
25+
}
26+
27+
// Prevent double initialization
28+
if (initialized) {
29+
console.warn('[Plausible] Already initialized');
30+
return;
31+
}
32+
33+
const { domain, apiHost, trackLocalhost = false } = config;
34+
35+
try {
36+
init({
37+
domain,
38+
// If apiHost is provided, use it as the endpoint
39+
...(apiHost && { endpoint: `${apiHost}/event` }),
40+
// Disable tracking on localhost unless explicitly enabled
41+
captureOnLocalhost: trackLocalhost,
42+
// Auto-capture pageviews
43+
autoCapturePageviews: true,
44+
// Track file downloads
45+
fileDownloads: true,
46+
// Track outbound links
47+
outboundLinks: true
48+
});
49+
50+
initialized = true;
51+
console.log('[Plausible] Initialized successfully');
52+
} catch (error) {
53+
console.error('[Plausible] Initialization failed:', error);
54+
}
55+
}
56+
57+
/**
58+
* Track a custom event in Plausible.
59+
*
60+
* @param eventName - Name of the event to track
61+
* @param props - Optional properties to attach to the event
62+
* @param revenue - Optional revenue tracking data
63+
*
64+
* @example
65+
* ```ts
66+
* // Simple event
67+
* track('signup');
68+
*
69+
* // Event with properties
70+
* track('signup', { tier: 'pro', plan: 'monthly' });
71+
*
72+
* // Event with revenue
73+
* track('purchase', { product: 'pro-plan' }, { amount: 29.99, currency: 'USD' });
74+
* ```
75+
*/
76+
export function track(
77+
eventName: string,
78+
props?: Record<string, string | number | boolean>,
79+
revenue?: { amount: number; currency: string }
80+
): void {
81+
if (!browser) {
82+
return;
83+
}
84+
85+
if (!initialized) {
86+
console.warn('[Plausible] Not initialized. Call initPlausible() first.');
87+
return;
88+
}
89+
90+
try {
91+
trackEvent(eventName, {
92+
...(props && { props }),
93+
...(revenue && { revenue })
94+
});
95+
} catch (error) {
96+
console.error(`[Plausible] Failed to track event "${eventName}":`, error);
97+
}
98+
}

0 commit comments

Comments
 (0)