@plainapps/analytics-svelte
v1.0.2
Published
Svelte stores and actions for Plain Web Analytics - privacy-focused, cookie-free analytics
Maintainers
Readme
@plainapps/analytics-svelte
Svelte stores and actions for Plain Web Analytics - privacy-focused, cookie-free web analytics.
Features
- 📊 Svelte Stores - Reactive stores for analytics state
- 🎯 Action Directives - Declarative tracking with
use:track - 🛤️ SvelteKit Support - Built-in SSR considerations
- ⚡ Lightweight - Tree-shakeable, minimal bundle impact
- 🔄 Context API - Share analytics across component hierarchies
- 📝 TypeScript - Full TypeScript support with type definitions
Installation
npm install @plainapps/analytics-svelte
# or
yarn add @plainapps/analytics-svelte
# or
pnpm add @plainapps/analytics-svelteQuick Start
Option 1: Stores (Recommended)
The simplest approach using Svelte stores:
<!-- +layout.svelte -->
<script>
import { onMount } from 'svelte';
import { initAnalytics } from '@plainapps/analytics-svelte';
onMount(() => {
initAnalytics({ siteId: 'pwa_site_abc123' });
});
</script>
<slot />Track events anywhere:
<script>
import { trackEvent, trackGoal, isInitialized } from '@plainapps/analytics-svelte';
function handleSignup() {
trackEvent('signup_click', { source: 'homepage' });
}
function handlePurchase(amount) {
trackGoal('purchase', { revenue: amount * 100 }); // cents
}
</script>
<button on:click={handleSignup} disabled={!$isInitialized}>
Sign Up
</button>Option 2: Action Directives
Declarative tracking without writing event handlers:
<script>
import { track, trackGoalAction } from '@plainapps/analytics-svelte';
</script>
<!-- Track clicks -->
<button use:track={{ event: 'signup_click', properties: { source: 'homepage' } }}>
Sign Up
</button>
<!-- Track goals -->
<button use:trackGoalAction={{ goal: 'purchase', revenue: 9900 }}>
Buy Now - $99
</button>
<!-- Track on different events -->
<input use:track={{ event: 'search_focus', on: 'focus' }} placeholder="Search..." />
<!-- Track only once -->
<div use:track={{ event: 'banner_view', on: 'mouseenter', once: true }}>
Promotional Banner
</div>Option 3: Context API
For sharing analytics across component hierarchies:
<!-- +layout.svelte -->
<script>
import { onMount } from 'svelte';
import { createPlainAnalytics, setAnalyticsContext } from '@plainapps/analytics-svelte';
const analytics = createPlainAnalytics({ siteId: 'pwa_site_abc123' });
setAnalyticsContext(analytics);
onMount(() => {
analytics.init();
});
</script>
<slot /><!-- ChildComponent.svelte -->
<script>
import { getAnalyticsContext } from '@plainapps/analytics-svelte';
const { trackEvent, isInitialized } = getAnalyticsContext();
let initialized = false;
isInitialized.subscribe(v => initialized = v);
</script>
<button on:click={() => trackEvent('child_click')} disabled={!initialized}>
Track from Child
</button>SvelteKit Integration
Basic Setup
<!-- src/routes/+layout.svelte -->
<script>
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { initAnalytics } from '@plainapps/analytics-svelte';
onMount(() => {
if (browser) {
initAnalytics({ siteId: 'pwa_site_abc123' });
}
});
</script>
<slot />Route Change Tracking
<!-- src/routes/+layout.svelte -->
<script>
import { onMount, afterNavigate } from 'svelte';
import { browser } from '$app/environment';
import { initAnalytics, trackPageview } from '@plainapps/analytics-svelte';
onMount(() => {
if (browser) {
initAnalytics({ siteId: 'pwa_site_abc123', autoPageview: false });
}
});
afterNavigate(() => {
trackPageview();
});
</script>
<slot />With SvelteKit's page Store
<script>
import { page } from '$app/stores';
import { browser } from '$app/environment';
import { initAnalytics, trackPageview, isInitialized } from '@plainapps/analytics-svelte';
import { onMount } from 'svelte';
onMount(() => {
if (browser) {
initAnalytics({ siteId: 'pwa_site_abc123', autoPageview: false });
}
});
// Track pageviews reactively
$: if ($isInitialized && browser) {
trackPageview($page.url.pathname);
}
</script>Vite Setup
No special configuration needed:
<!-- App.svelte -->
<script>
import { onMount } from 'svelte';
import { initAnalytics } from '@plainapps/analytics-svelte';
onMount(() => {
initAnalytics({ siteId: 'pwa_site_abc123' });
});
</script>API Reference
Stores
initAnalytics(options)
Initialize analytics. Call in onMount or client-side code.
interface PlainAnalyticsOptions {
siteId: string; // Required: Your site key
apiEndpoint?: string; // Custom API endpoint
autoPageview?: boolean; // Auto-track initial pageview (default: true)
hashMode?: boolean; // Track hash changes (default: false)
debug?: boolean; // Enable debug logging (default: false)
}trackPageview(url?)
Track a pageview manually.
import { trackPageview } from '@plainapps/analytics-svelte';
trackPageview(); // Track current URL
trackPageview('/custom-url'); // Track custom URLtrackEvent(name, properties?)
Track a custom event.
import { trackEvent } from '@plainapps/analytics-svelte';
trackEvent('button_click', { button: 'signup', variant: 'blue' });trackGoal(goalId, options?)
Track a goal conversion.
import { trackGoal } from '@plainapps/analytics-svelte';
trackGoal('purchase', {
revenue: 9900, // Revenue in cents
properties: { product: 'pro-plan' }
});setEnabled(enabled)
Enable or disable tracking.
import { setEnabled } from '@plainapps/analytics-svelte';
setEnabled(false); // Disable tracking
setEnabled(true); // Enable trackingReadable Stores
import { isInitialized, isEnabled, config } from '@plainapps/analytics-svelte';
$isInitialized // boolean - Whether analytics is ready
$isEnabled // boolean - Whether tracking is enabled
$config // AnalyticsConfig | null - Current configurationActions
use:track
Track events declaratively.
<button use:track={{ event: 'click', properties: { btn: 'cta' } }}>
Click
</button>
<input use:track={{ event: 'focus', on: 'focus' }} />
<div use:track={{ event: 'hover', on: 'mouseenter', once: true }}>
Hover me
</div>use:trackGoalAction
Track goals declaratively.
<button use:trackGoalAction={{ goal: 'signup', properties: { plan: 'pro' } }}>
Sign Up
</button>
<button use:trackGoalAction={{ goal: 'purchase', revenue: 9900 }}>
Buy Now
</button>use:trackVisible
Track when an element enters the viewport.
<section use:trackVisible={{ event: 'pricing_viewed' }}>
Pricing content...
</section>
<div use:trackVisible={{ event: 'product_impression', properties: { id: 'abc' } }}>
Product Card
</div>Context API
createPlainAnalytics(options)
Create an analytics instance for context.
import { createPlainAnalytics, setAnalyticsContext } from '@plainapps/analytics-svelte';
const analytics = createPlainAnalytics({ siteId: 'pwa_site_abc123' });
setAnalyticsContext(analytics);
// Initialize in onMount
analytics.init();getAnalyticsContext()
Get analytics from context (throws if not found).
import { getAnalyticsContext } from '@plainapps/analytics-svelte';
const { trackEvent, isInitialized } = getAnalyticsContext();hasAnalyticsContext()
Check if context exists (doesn't throw).
import { hasAnalyticsContext } from '@plainapps/analytics-svelte';
if (hasAnalyticsContext()) {
// Context is available
}Examples
Track Form Submission
<script>
import { trackEvent, trackGoal } from '@plainapps/analytics-svelte';
async function handleSubmit() {
const success = await submitForm();
if (success) {
trackEvent('form_submit', { form: 'contact' });
trackGoal('lead_capture');
}
}
</script>
<form on:submit|preventDefault={handleSubmit}>
<input type="email" placeholder="Email" />
<button type="submit">Subscribe</button>
</form>Conditional Tracking (GDPR)
<script>
import { setEnabled, isEnabled } from '@plainapps/analytics-svelte';
</script>
<label>
<input
type="checkbox"
checked={$isEnabled}
on:change={(e) => setEnabled(e.target.checked)}
/>
Allow analytics
</label>Track E-commerce Purchase
<script>
import { trackGoal } from '@plainapps/analytics-svelte';
async function handleCheckout(cart) {
const order = await processPayment(cart);
trackGoal('purchase', {
revenue: order.total * 100, // cents
properties: {
order_id: order.id,
items: cart.items.length,
},
});
}
</script>Track Scroll Depth
<script>
import { onMount } from 'svelte';
import { trackEvent, isInitialized } from '@plainapps/analytics-svelte';
const tracked = { 25: false, 50: false, 75: false, 100: false };
onMount(() => {
function handleScroll() {
if (!$isInitialized) return;
const depth = Math.round(
(window.scrollY / (document.body.scrollHeight - window.innerHeight)) * 100
);
for (const threshold of [25, 50, 75, 100]) {
if (depth >= threshold && !tracked[threshold]) {
tracked[threshold] = true;
trackEvent('scroll_depth', { depth: threshold });
}
}
}
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
});
</script>TypeScript
Full TypeScript support is included:
import type {
PlainAnalyticsOptions,
PlainAnalyticsContext,
PlainAnalyticsPlugin,
GoalOptions,
TrackActionOptions,
TrackGoalActionOptions,
EventProperties,
Goal,
} from '@plainapps/analytics-svelte';License
MIT
