SDK Reference
Simplist provides server-side analytics that are privacy-friendly, adblocker-proof, and GDPR compliant. Track page views, engagement metrics, and get detailed insights.
| Method | Description | Returns |
|---|---|---|
| Track a new page view | Promise<PageViewResponse> | |
| Update an existing page view | Promise<{ success: boolean }> | |
| Get analytics statistics | Promise<ApiResponse<AnalyticsStats>> |
Initialize tracking for a new page view. Call this when a user lands on an article page.
Method Signature
async client.analytics.track(data: PageViewData): Promise<PageViewResponse>| Property | Type | Description | Default |
|---|---|---|---|
slug* | string | Article slug (required) | - |
sessionId | string | Unique session identifier | - |
pageUrl | string | Full page URL | - |
pageTitle | string | Page title | - |
referrer | string | Referrer URL | - |
utmSource | string | UTM source | - |
utmMedium | string | UTM medium | - |
utmCampaign | string | UTM campaign | - |
screenWidth | number | Screen width in pixels | - |
screenHeight | number | Screen height in pixels | - |
timeOnPage | number | Time spent in seconds | - |
scrollDepth | number | Scroll depth (0-100%) | - |
exitPosition | number | Exit position (0-100%) | - |
bounced | boolean | Whether user bounced | - |
events | PageEvent[] | Custom events | - |
fetchGeo | boolean | Fetch geolocation from IP | - |
| Property | Type | Description | Default |
|---|---|---|---|
id* | string | Page view ID for updates | - |
success* | boolean | Whether tracking succeeded | - |
const response = await client.analytics.track({
slug: 'getting-started',
sessionId: generateSessionId(), // Your session ID logic
pageUrl: 'https://myblog.com/blog/getting-started',
pageTitle: 'Getting Started',
referrer: document.referrer,
screenWidth: window.innerWidth,
screenHeight: window.innerHeight,
timeOnPage: 0,
scrollDepth: 0,
fetchGeo: true
})
// Store the ID for later updates
const { pageViewId, visitorId, sessionId } = responseUpdate an existing page view with engagement metrics. Call this periodically or when the user leaves.
Method Signature
async client.analytics.update(pageViewId: string, data: Partial<PageViewData>): Promise<{ success: boolean }>// Update every 30 seconds
setInterval(async () => {
await client.analytics.update(pageViewId, {
timeOnPage: getTimeOnPage(),
scrollDepth: getScrollDepth(),
events: getCustomEvents()
})
}, 30000)
// Final update on page unload
window.addEventListener('beforeunload', async () => {
await client.analytics.update(pageViewId, {
timeOnPage: getTimeOnPage(),
scrollDepth: getScrollDepth(),
exitPosition: getScrollDepth(),
bounced: getTimeOnPage() < 5
})
})Retrieve analytics statistics for your project.
Method Signature
async client.analytics.getStats(options?: { days?: number }): Promise<ApiResponse<AnalyticsStats>>| Property | Type | Description | Default |
|---|---|---|---|
days | number | Number of days to include | 30 |
| Property | Type | Description | Default |
|---|---|---|---|
period* | { days: number, startDate: string, endDate: string } | - | - |
summary* | { totalViews: number, uniqueVisitors: number, avgViewsPerVisitor: number } | - | - |
requestSource | { sdk: number, direct: number } | Percentage breakdown | - |
topArticles* | Array<{ articleId: string, title: string, slug: string, views: number }> | - | - |
topCountries* | Array<{ country: string, views: number }> | - | - |
const { data: stats } = await client.analytics.getStats({ days: 7 })
console.log(`Period: ${stats.period.days} days`)
console.log(`Total views: ${stats.summary.totalViews}`)
console.log(`Unique visitors: ${stats.summary.uniqueVisitors}`)
console.log(`Avg views per visitor: ${stats.summary.avgViewsPerVisitor.toFixed(2)}`)
console.log('\nTop 5 Articles:')
stats.topArticles.slice(0, 5).forEach((article, i) => {
console.log(`${i + 1}. ${article.title} (${article.views} views)`)
})
console.log('\nTop Countries:')
stats.topCountries.forEach(country => {
console.log(`- ${country.country}: ${country.views} views`)
})Track custom events like button clicks, video plays, or form submissions.
| Property | Type | Description | Default |
|---|---|---|---|
type* | string | Event type (e.g., 'click', 'video_play') | - |
data | Record<string, any> | Event-specific data | - |
position | number | Scroll position when event occurred | - |
element | string | Element identifier | - |
timeOffset | number | Time since page load (ms) | - |
const events: PageEvent[] = [
{
type: 'button_click',
element: 'cta-button',
position: 45,
timeOffset: 15000,
data: { buttonText: 'Get Started' }
},
{
type: 'video_play',
element: 'intro-video',
position: 30,
timeOffset: 8000,
data: { videoId: 'intro-123', duration: 120 }
},
{
type: 'link_click',
element: 'external-link',
data: { href: 'https://example.com', text: 'Learn more' }
}
]
await client.analytics.track({
slug: 'my-article',
events
})"use client"
import { SimplistClient } from "@simplist.blog/sdk"
import { useEffect, useState } from "react"
import { v4 as uuid } from "uuid"
export function AnalyticsTracker({ slug }: { slug: string }) {
const [pageViewId, setPageViewId] = useState<string | null>(null)
const [startTime] = useState(Date.now())
useEffect(() => {
// Uses SIMPLIST_API_KEY from environment variables
const client = new SimplistClient()
// Get or create session ID
const getSessionId = () => {
let sessionId = sessionStorage.getItem('simplist_session')
if (!sessionId) {
sessionId = uuid()
sessionStorage.setItem('simplist_session', sessionId)
}
return sessionId
}
// Initial tracking
const initTracking = async () => {
const response = await client.analytics.track({
slug,
sessionId: getSessionId(),
pageUrl: window.location.href,
pageTitle: document.title,
referrer: document.referrer,
screenWidth: window.innerWidth,
screenHeight: window.innerHeight,
timeOnPage: 0,
scrollDepth: 0,
fetchGeo: true
})
setPageViewId(response.id)
}
initTracking()
// Update metrics every 30 seconds
const updateInterval = setInterval(async () => {
if (!pageViewId) return
const timeOnPage = Math.floor((Date.now() - startTime) / 1000)
const scrollDepth = Math.round(
(window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100
)
await client.analytics.update(pageViewId, {
timeOnPage,
scrollDepth
})
}, 30000)
// Final update on unmount
return () => {
clearInterval(updateInterval)
if (pageViewId) {
const timeOnPage = Math.floor((Date.now() - startTime) / 1000)
const scrollDepth = Math.round(
(window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)) * 100
)
client.analytics.update(pageViewId, {
timeOnPage,
scrollDepth,
exitPosition: scrollDepth,
bounced: timeOnPage < 5
})
}
}
}, [slug, pageViewId, startTime])
return null
}These SDK methods use the following API endpoints:
track()→ POST/v1/analytics/trackupdate()→ PUT/v1/analytics/track/:idgetStats()→ GET/v1/analytics/stats
See the REST API documentation for direct HTTP access.
- No cookies: All tracking is server-side
- Anonymous: No personal data collected
- IP-based geolocation: Optional and anonymized
- GDPR compliant: Data retention policies in place
- Adblocker-proof: Server-side tracking works everywhere
Quick Help
Use useEffect to call track() on mount, or create a Server Action wrapper. The SDK is server-side only, but you can send data from the client to a server endpoint that calls the SDK.
Only call update() when the user leaves the page to send final metrics (time on page, scroll depth). Call track() once on page load to create the initial pageview.
Yes! Server-side tracking in Next.js Server Components works without client JavaScript. Analytics are captured during SSR, making them reliable and ad-blocker-proof.