Skip to content

Latest commit

 

History

History
622 lines (490 loc) · 27.2 KB

File metadata and controls

622 lines (490 loc) · 27.2 KB

Plausible Analytics Tracking

This document provides a comprehensive overview of Plausible Analytics implementation for anyplot.ai, including all tracked events, user interactions, and the required Plausible dashboard configuration.

Setup

Location: app/index.html

  • Self-hosted Plausible script loaded via /js/script.js
  • Custom endpoint: /api/event (proxied through nginx to avoid adblockers)
  • Manual pageview tracking: autoCapturePageviews: false
  • Production-only: Only tracks on anyplot.ai domain
  • Privacy-focused: No cookies, GDPR-compliant

Page Views

Implementation: Query parameters converted to URL path segments for better analytics segmentation.

Multi-Language URL Strategy

Cutover date: 2026-04-20

Spec URLs follow the three-tier structure /{specId}[/{language}[/{library}]], so the spec slug — the actual SEO entity — sits at the URL root and the language slots between spec and library:

  • Root / and reserved static pages (/plots, /specs, /libraries, /palette, /about, /legal, /mcp, /stats) are un-prefixed.
  • Cross-language hub: /{spec_id} (lists every implementation across all languages).
  • Language overview: /{spec_id}/{language} (e.g. /scatter-basic/python).
  • Implementation detail: /{spec_id}/{language}/{library} (e.g. /scatter-basic/python/matplotlib).
  • Interactive view is no longer a separate route — the detail page toggles between static preview and iframe via ?view=interactive. The query string is not included in Plausible URLs (canonical only).
  • Marketing subdomain python.anyplot.ai rewrites internally; canonical in HTML points back to anyplot.ai/{spec_id}/python[/{library}] so all pageviews show up under the main domain.

Historical data before 2026-04-14 uses un-prefixed paths (/{spec_id}); data between 2026-04-14 and 2026-04-20 uses the legacy /python/{spec_id}[/{library}] prefix. Both ranges remain visible in Plausible but are no longer produced.

Filter-Based Pageviews

Filters create dynamic URLs with the following format:

https://anyplot.ai/{category}/{value}/{category}/{value}/...

On spec routes, the spec/language/library prefix is preserved before the filter segments:

https://anyplot.ai/{spec_id}/{language}/{library}/{category}/{value}/...

Ordered categories: lib, spec, plot, data, dom, feat, dep, tech, pat, prep, style

Examples (root homepage):

  • /?lib=matplotlibhttps://anyplot.ai/lib/matplotlib
  • /?lib=matplotlib&plot=scatterhttps://anyplot.ai/lib/matplotlib/plot/scatter
  • /?lib=matplotlib,seabornhttps://anyplot.ai/lib/matplotlib,seaborn (OR logic)
  • /?lib=matplotlib&lib=seabornhttps://anyplot.ai/lib/matplotlib/lib/seaborn (AND logic)

Examples (spec routes):

  • /scatter-basic/python?lib=matplotlibhttps://anyplot.ai/scatter-basic/python/lib/matplotlib

Benefits:

  • Plausible shows popular filter combinations
  • No manual event tracking needed for filter changes
  • URL structure clearly shows user's browsing context

Pages

URL Description
/ Home page (no filters)
/plots Plots page (filter grid of all implementations)
/specs Specs page (alphabetical spec list)
/libraries Libraries listing
/palette Color palette reference
/about About page
/legal Legal notice, privacy policy, transparency
/mcp MCP server documentation (AI assistant integration)
/stats Platform statistics (library scores, coverage, tags, top implementations)
/{spec_id} Cross-language spec hub (all implementations across all languages)
/{spec_id}/{language} Language overview (all libraries for that language)
/{spec_id}/{language}/{library} Implementation detail (preview ↔ interactive toggle)

Total pageview tracking: Automated via trackPageview() in all pages

Custom Events

Conversions

Event Name Properties Where Description
copy_code spec, library, method, page ImageCard.tsx, SpecPage.tsx, SpecTabs.tsx User copies code to clipboard
download_image spec, library, page SpecPage.tsx User downloads PNG image

Copy methods:

  • card: Quick copy button on image card (home grid)
  • image: Copy button on main image (spec page)
  • tab: Copy button in Code tab

Page values (for user journey tracking):

  • home: HomePage grid view
  • spec_overview: SpecPage showing all library implementations
  • spec_detail: SpecPage showing single library implementation

Discovery

Event Name Properties Where Description
search query, category FilterBar.tsx User searches and selects value
search_no_results query FilterBar.tsx Search query returns no results (debounced 200ms)

Feature Usage

Event Name Properties Where Description
random_filter category, value, method useFilterState.ts User triggers random filter
filter_remove category, value useFilterState.ts User removes a filter
grid_resize size ToolbarActions.tsx User toggles between normal/compact view
tab_toggle action, tab, library SpecTabs.tsx User opens or closes a tab
plot_rotate spec SpecsListPage.tsx User clicks image on specs page to rotate library
open_interactive spec, library SpecOverview.tsx, SpecDetailView.tsx User opens interactive HTML view
suggest_spec - SpecsListPage.tsx User clicks the spec.suggest() link on the specs list page. The mirror link on the landing page emits nav_click with source: suggest_spec_link instead.
report_issue spec, library? SpecPage.tsx User clicks "report issue" link
tag_click param, value, source SpecTabs.tsx User clicks a tag chip to filter
theme_toggle to MastheadRule.tsx User cycles tri-state theme mode (tosystem, light, dark). The cycle order is system → light → dark → system.
potd_dismiss spec, library PlotOfTheDay.tsx User dismisses the plot-of-the-day banner
view_mode_change mode, library SpecDetailView.tsx User toggles preview ↔ interactive view inside a spec detail. modepreview, interactive. Fires on every toggle in either direction (cf. open_interactive, which only fires when the interactive HTML is opened in a new tab).
library_click source, library LibrariesPage.tsx User clicks a library card on /libraries to navigate to its filtered plots view. source is libraries_page from this entry point.
stats_top_impl_click spec, library StatsPage.tsx User clicks a "top implementation" thumbnail on /stats to jump into its spec detail.

Landing Page Navigation (nav_click)

A single event captures every clickable surface on the chrome and the new editorial landing page so we can answer "where do users go from / and via which UI element". One event, one event-property pair: source (which UI element was clicked) + target (where it leads). Some sources additionally carry spec, library, or value for richer breakdowns.

source value Where Target
nav_specs / nav_plots / nav_libraries / nav_stats / nav_palette / nav_mcp NavBar.tsx top-level menu bar
nav_logo NavBar.tsx logo → /
nav_search NavBar.tsx plots.search() button → /plots?focus=search
masthead_logo / masthead_branch / masthead_release MastheadRule.tsx masthead ~/anyplot.ai · main · v1.x.x
breadcrumb MastheadRule.tsx breadcrumb segments on non-landing routes
hero_cta_browse / hero_mcp / hero_github HeroSection.tsx hero call-to-action + secondary links
potd_image / potd_title / potd_source_link PlotOfTheDay.tsx dismissible plot-of-the-day banner
potd_terminal_image / potd_terminal_filename / potd_terminal_github PlotOfTheDayTerminal.tsx hero terminal-framed POTD
featured_thumb LandingPage.tsx featured plot grid
library_card LandingPage.tsx library cards (carries value=<library_id>)
section_header SectionHeader.tsx specs.all() / libraries.all() / palette.explore() headers
specs_more_link LandingPage.tsx + N more in the catalogue →
suggest_spec_link LandingPage.tsx spec.suggest() GitHub-issue link
palette_okabe_ito LandingPage.tsx external Okabe & Ito reference

Random methods:

  • click: Shuffle icon clicked
  • space: Spacebar pressed
  • doubletap: Mobile double-tap gesture

Grid sizes:

  • normal: Larger cards (1-3 columns)
  • compact: Smaller cards (2-6 columns)

Tab toggle actions:

  • open: User opened a tab
  • close: User closed a tab

Tab names: code, specification, implementation, quality

External/Internal Link Events

Event Name Properties Where Description
external_link destination, spec?, library? Footer.tsx, LegalPage.tsx User clicks external link
internal_link destination, spec?, library? Footer.tsx User clicks internal link in footer

External destinations (Footer): github, stats, linkedin External destinations (LegalPage): linkedin, x, github_personal Internal destinations: mcp, legal

Performance (Core Web Vitals)

Event Name Properties Where Description
LCP value, rating reportWebVitals.ts Largest Contentful Paint (rounded to nearest 100ms)
CLS value, rating reportWebVitals.ts Cumulative Layout Shift (2 decimal places)
INP value, rating reportWebVitals.ts Interaction to Next Paint (rounded to nearest 50ms)

Rating values: good, needs-improvement, poor (per web-vitals thresholds)

CWV tracking is production-only and dynamically imported (zero dev/bundle cost).


Server-Side og:image Tracking

Social media bots (Twitter, WhatsApp, Teams, etc.) don't execute JavaScript, so og:image requests can only be tracked server-side.

Architecture

All og:images are routed through the API for tracking:

Bot requests page → nginx detects bot → SEO proxy serves HTML with og:image URL
                                                            ↓
                                          https://api.anyplot.ai/og/{endpoint}.png
                                                            ↓
                                          track_og_image() → Plausible Events API
                                                            ↓
                                          Return image (fire-and-forget tracking)

Implementation: api/analytics.py (server-side Plausible tracking)

og:image Event

Event Name Properties Description
og_image_view page, platform, spec?, language?, library?, filter_*? Bot requested og:image

Properties

Property Values Description
page home, plots, spec_overview, spec_detail Page type
platform See list below Detected platform from User-Agent
spec Specification ID Only for spec pages
language Language slug (e.g. python) Only for spec detail pages
library Library ID Only for spec detail pages
filter_* Filter value Dynamic props for filtered URLs (e.g., filter_lib, filter_dom)

Platform Detection (27 platforms)

Social Media: twitter, facebook, linkedin, pinterest, reddit, tumblr, mastodon

Messaging Apps: slack, discord, telegram, whatsapp, signal, viber, skype, teams, snapchat

Search Engines: google, bing, yandex, duckduckgo, baidu, apple

Link Preview Services: embedly, quora, outbrain, rogerbot, showyoubot

Fallback: unknown

WhatsApp Variant Detection

Some apps (Signal, others) use a WhatsApp User-Agent to bypass rate limits (Issue #10060). We distinguish real WhatsApp from spoofed requests by version format:

Platform User-Agent Example Detection
whatsapp WhatsApp/2.23.18.78 i 3+ part version = verified WhatsApp
whatsapp-lite WhatsApp or WhatsApp/2 Simplified UA = Signal or other spoofers

API Endpoints

Endpoint Description Tracking
/og/home.png Static og:image for home page page=home, filter_* from query params
/og/plots.png Static og:image for plots page page=plots
/og/{spec_id}.png Collage og:image for spec overview page=spec_overview, spec
/og/{spec_id}/{language}/{library}.png Branded og:image for implementation page=spec_detail, spec, language, library

Filter Tracking for Shared URLs

When users share filtered URLs (e.g., https://anyplot.ai/?lib=plotly&dom=statistics), the filters are passed to the og:image endpoint:

og:image URL: https://api.anyplot.ai/og/home.png?lib=plotly,matplotlib&dom=statistics
                                                  ↓
Tracked props: { page: "home", platform: "twitter", filter_lib: "plotly,matplotlib", filter_dom: "statistics" }

Note: Each filter category becomes a separate prop (filter_lib, filter_dom, etc.) to handle comma-separated values.


Plausible Dashboard Configuration

Required Custom Properties

To see event properties in Plausible dashboard, you MUST register them as custom properties.

Go to: Plausible Dashboard → Site Settings → Custom Properties → Add Property

Properties to Register

Property Description Used By Events
spec Plot specification ID copy_code, download_image, plot_rotate, external_link, internal_link, open_interactive, report_issue, tag_click, og_image_view
language Language slug (python, future: julia, r, matlab) og_image_view
library Library name (matplotlib, seaborn, etc.) copy_code, download_image, external_link, internal_link, open_interactive, tab_toggle, og_image_view
method Action method (card, image, tab, click, space, doubletap) copy_code, random_filter
page Page context (home, plots, spec_overview, spec_detail) copy_code, download_image, og_image_view
platform Bot/platform name (twitter, whatsapp, teams, etc.) og_image_view
category Filter category (lib, spec, plot, data, dom, feat, dep, tech, pat, prep, style) search, random_filter, filter_remove
value Filter value random_filter, filter_remove, tag_click
query Search query text search, search_no_results
destination Link target (github, plausible, stats, compare, linkedin, mcp, legal) external_link, internal_link
tab Tab name (code, specification, implementation, quality) tab_toggle
action Toggle action (open, close) tab_toggle
size Grid size (normal, compact) grid_resize
param URL parameter name for tag tag_click
source Source UI element / page context tag_click, nav_click
target Click destination (route or external label) nav_click
to New mode after toggle (system / light / dark) theme_toggle
mode Spec detail view mode (preview / interactive) view_mode_change
theme Ambient effective theme attached to every pageview & event (dark / light) — resolved from the tri-state mode so OS-followers still split cleanly all events (set in RootLayout via setAnalyticsAmbientProps)
rating CWV rating (good, needs-improvement, poor) LCP, CLS, INP
filter_lib Library filter value (for og:image) og_image_view
filter_spec Specification filter value (for og:image) og_image_view
filter_plot Plot type filter value (for og:image) og_image_view
filter_data Data type filter value (for og:image) og_image_view
filter_dom Domain filter value (for og:image) og_image_view
filter_feat Features filter value (for og:image) og_image_view
filter_dep Dependencies filter value (for og:image) og_image_view
filter_tech Techniques filter value (for og:image) og_image_view
filter_pat Patterns filter value (for og:image) og_image_view
filter_prep Dataprep filter value (for og:image) og_image_view
filter_style Styling filter value (for og:image) og_image_view

Goals Configuration

Go to: Plausible Dashboard → Site Settings → Goals → Add Goal

Recommended Goals

Goal Name Type Description
copy_code Custom Event Track code copies (primary conversion)
download_image Custom Event Track image downloads
search Custom Event Track successful searches
search_no_results Custom Event Track failed searches (content gaps)
random_filter Custom Event Track random filter usage
filter_remove Custom Event Track filter removal
grid_resize Custom Event Track view preference
tab_toggle Custom Event Track tab interactions
external_link Custom Event Track outbound clicks
internal_link Custom Event Track internal navigation links
open_interactive Custom Event Track interactive mode usage
suggest_spec Custom Event Track spec suggestion clicks
report_issue Custom Event Track issue report clicks
tag_click Custom Event Track tag filter clicks
plot_rotate Custom Event Track plot image rotation on specs page
nav_click Custom Event Track which UI element on landing/chrome leads users off the root
theme_toggle Custom Event Track dark/light theme switches
potd_dismiss Custom Event Track plot-of-the-day banner dismissals
view_mode_change Custom Event Track preview ↔ interactive toggles in spec detail
library_click Custom Event Track library-card clicks on the libraries page
stats_top_impl_click Custom Event Track clicks on top-quality implementation thumbnails on /stats
og_image_view Custom Event Track og:image requests from social media bots
LCP Custom Event Largest Contentful Paint (Core Web Vital)
CLS Custom Event Cumulative Layout Shift (Core Web Vital)
INP Custom Event Interaction to Next Paint (Core Web Vital)

Funnels (Optional)

Example funnel: Home → Spec → Copy

  1. Pageview / (home)
  2. Pageview /{spec_id}/{language}/{library} (spec detail)
  3. copy_code event

Dashboard Widgets

Recommended custom widgets:

  1. Top Specs Copied: copy_code breakdown by spec
  2. Popular Libraries: copy_code breakdown by library
  3. Copy Journey: copy_code breakdown by page
  4. Search Terms: search breakdown by query
  5. Missing Content: search_no_results breakdown by query
  6. View Preference: grid_resize breakdown by size
  7. CWV Performance: LCP / CLS / INP breakdown by rating

User Journey Tracking

Understanding page Property

The page property tracks where users perform actions to understand their journey:

User lands on anyplot.ai
    │
    ├─→ Home (grid view)
    │   └─→ copy_code { page: 'home' }
    │
    ├─→ Cross-Language Hub (/{spec_id})
    │   └─→ copy_code { page: 'spec_hub' }
    │
    ├─→ Language Overview (/{spec_id}/{language})
    │   └─→ copy_code { page: 'spec_overview' }
    │   └─→ download_image { page: 'spec_overview' }
    │
    └─→ Implementation Detail (/{spec_id}/{language}/{library})
        └─→ copy_code { page: 'spec_detail' }
        └─→ download_image { page: 'spec_detail' }
        └─→ open_interactive { spec, language, library }

Journey Examples in Plausible

Q: Do users copy from search results or spec pages?

  • Filter copy_code by page property
  • home = direct from search/browse
  • spec_overview = after viewing all implementations
  • spec_detail = after deep-diving into one library

Q: Which library implementations are most downloaded?

  • Filter download_image by library property
  • Filter by page to see if users download from overview or detail

Complete Event Reference

Events Summary Table

Event Properties Code Location
copy_code spec, library, method, page ImageCard.tsx, SpecPage.tsx, SpecTabs.tsx
download_image spec, library, page SpecPage.tsx
search query, category FilterBar.tsx
search_no_results query FilterBar.tsx
random_filter category, value, method useFilterState.ts
filter_remove category, value useFilterState.ts
grid_resize size ToolbarActions.tsx
tab_toggle action, tab, library SpecTabs.tsx
tag_click param, value, source SpecTabs.tsx
plot_rotate spec SpecsListPage.tsx
open_interactive spec, library SpecOverview.tsx, SpecDetailView.tsx
suggest_spec - SpecsListPage.tsx (LandingPage mirror attributed via nav_click with source: suggest_spec_link)
report_issue spec, library? SpecPage.tsx
external_link destination, spec?, library? Footer.tsx, LegalPage.tsx
internal_link destination, spec, library Footer.tsx
nav_click source, target, spec?, library?, value? NavBar, MastheadRule, HeroSection, SectionHeader, PlotOfTheDay, PlotOfTheDayTerminal, LandingPage
theme_toggle to MastheadRule.tsx
potd_dismiss spec, library PlotOfTheDay.tsx
view_mode_change mode, library SpecDetailView.tsx
library_click source, library LibrariesPage.tsx
stats_top_impl_click spec, library StatsPage.tsx
LCP value, rating reportWebVitals.ts
CLS value, rating reportWebVitals.ts
INP value, rating reportWebVitals.ts
og_image_view page, platform, spec?, language?, library?, filter_*? api/analytics.py (server-side)

Total: 25 client-side + 1 server-side = 26 events

Every pageview and event additionally carries a theme ambient prop (dark / light). Set in RootLayout via setAnalyticsAmbientProps whenever the user toggles the theme — register theme as a custom property to see the dark-vs-light split per URL.


Property Values Reference

spec Values

Any valid specification ID (e.g., scatter-basic, heatmap-correlation, bar-grouped)

library Values

matplotlib | seaborn | plotly | bokeh | altair | plotnine | pygal | highcharts | letsplot

method Values

card      # ImageCard copy button (home grid)
image     # SpecPage image copy button
tab       # SpecTabs code tab copy button
click     # Random icon clicked
space     # Spacebar pressed
doubletap # Mobile double-tap

page Values

home          # HomePage grid view (client) or og:image home endpoint (server)
plots         # PlotsPage (server og:image only)
spec_overview # SpecPage showing all libraries
spec_detail   # SpecPage showing single library

platform Values (server-side og:image tracking only)

# Social Media
twitter | facebook | linkedin | pinterest | reddit | tumblr | mastodon

# Messaging Apps
slack | discord | telegram | whatsapp | signal | viber | skype | teams | snapchat

# Search Engines
google | bing | yandex | duckduckgo | baidu | apple

# Link Preview Services
embedly | quora | outbrain | rogerbot | showyoubot

# Fallback
unknown

category Values

# Spec-level (WHAT is visualized)
lib   # library filter
spec  # specification filter
plot  # plot_type filter
data  # data_type filter
dom   # domain filter
feat  # features filter

# Impl-level (HOW it is implemented)
dep   # dependencies filter
tech  # techniques filter
pat   # patterns filter
prep  # dataprep filter
style # styling filter

tab Values

code           # Python code tab
specification  # Spec details tab
implementation # AI implementation review tab
quality        # Quality score breakdown tab

destination Values

github          # GitHub repository link (Footer)
stats           # Plausible stats dashboard link (Footer)
linkedin        # LinkedIn profile link (Footer, LegalPage)
x               # X/Twitter profile link (LegalPage)
github_personal # Personal GitHub link (LegalPage)
mcp             # MCP documentation page (internal link, Footer)
legal           # Legal page (internal link, Footer)

size Values

normal   # Larger cards (1-3 columns)
compact  # Smaller cards (2-6 columns)

rating Values (Core Web Vitals)

good              # Within recommended thresholds
needs-improvement # Between good and poor thresholds
poor              # Exceeds poor threshold

Code Locations

  • Plausible setup: app/index.html (lines 59-68)
  • Analytics hook: app/src/hooks/useAnalytics.ts
  • Pageview building: buildPlausibleUrl() in useAnalytics.ts
  • Core Web Vitals: app/src/analytics/reportWebVitals.ts
  • Event tracking: Passed via onTrackEvent prop throughout component tree

Testing

Development: Tracking disabled (not on anyplot.ai domain)

Production testing:

  1. Open https://anyplot.ai
  2. Open browser console
  3. Check for Plausible script load
  4. Trigger events and verify in Plausible dashboard (may take 1-2 min)

Debug mode:

// In browser console
window.plausible = function(...args) { console.log('Plausible:', args); };

Implementation Checklist

  • Plausible script loaded
  • Manual pageview tracking
  • Filter-based URL generation
  • Code copy events with journey tracking (copy_code + page)
  • Download tracking (download_image + page)
  • Search events (search, search_no_results)
  • Random filter events (random_filter)
  • Filter removal tracking (filter_remove)
  • Grid size toggle tracking (grid_resize)
  • Tab interaction events (tab_toggle)
  • Tag click events (tag_click)
  • External link events (external_link)
  • Internal link events (internal_link)
  • Feature link events (open_interactive, suggest_spec, report_issue)
  • Plot rotation (plot_rotate)
  • Core Web Vitals tracking (LCP, CLS, INP)
  • Server-side og:image tracking (og_image_view) with platform detection
  • Landing-page navigation tracking (nav_click)
  • Theme tracking (theme_toggle event + theme ambient pageview prop)
  • Plot-of-the-day dismissal (potd_dismiss)

Plausible Dashboard Checklist

  • Register all custom properties (see table above, including rating, action, param, source, platform, filter_*)
  • Create goals for key events (including LCP, CLS, INP)
  • Set up funnels (optional)
  • Create custom dashboard widgets (optional)

Last Updated: 2026-04-25 Status: Production-ready with full journey tracking, Core Web Vitals, server-side og:image analytics, landing-page nav tracking, and theme analytics