📂 Screenshots not visible? Download the standalone version — single file, all screenshots embedded, works offline.

Measurement Plan

TNK Designs — Analytics implementation overview

Author
Guillermo García
Site URL
https://tnkproject.com/
Stack
Static HTML · Tailwind CSS · Vanilla JS
Analytics layer
Google Tag Manager + GA4
GTM Container
GTM-KW97DTMV · Account: tnk-project (6343762712)
GA4 Measurement ID
G-25V933JKJD
GA4 Stream
tnk-analytics-design-website · Stream ID: 13893341764 · https://tnkproject.com
Data layer library
analytics.js (shared, all pages)
Privacy
PII filtered · email SHA-256 hashed · no raw textarea
Pages instrumented
14 pages (8 with engagement)
Last updated
2026-03-24

Events implemented

All Parameters

Full parameter registry across all events

# Parameter Type Events Example value Notes

page_view

Fires on DOMContentLoaded on every page — reads window.TNK_PAGE · one row per unique page_category + page_type combination (6 of 11 pages shown)

select_content

Fires on all navigational clicks across the site

generate_lead

Fires on contact form submit — non-PII fields + SHA-256 hashed email

orbit_interaction

Fires on hover of the orbiting skills section on the Home page

post_engagement

Single event — fires on blog post pages for likes and comments. action distinguishes the interaction type.

UTM & Outbound Tracking — Frente 1

Campaign tracking and external link measurement for UTM templates and social/resource links

resource_download

Fires when user clicks on a downloadable resource link (Google Sheets UTM template, etc.)

Trigger: User clicks resource link with data-track-resource attribute · Frequency: Once per resource per session

Parameter Type Example Notes
content_type string "utm_template" Type of resource being downloaded
destination_url string https://docs.google.com/spreadsheets/... URL of the resource being downloaded
template_type string "utm_generator" Specific template type (optional)

outbound_click

Automatically detects and tracks clicks on all external links (social profiles, GitHub, external resources, etc.)

Trigger: User clicks external link · Frequency: Once per unique external domain per session

Parameter Type Example Notes
destination_domain string "linkedin.com" Domain only (no path or query params for privacy)
destination_url string https://www.linkedin.com/in/guillermo/ Full URL of the external link
link_text string "Follow on LinkedIn" Anchor text (max 100 chars)
section string "article_footer" Page section: article_footer, article_body, navbar, footer, etc.

Engagement Tracking — Frente 2

Scroll depth, reading time, and code copying on blog posts

scroll_depth

Fires at 25%, 50%, 75%, 100% scroll thresholds on every blog post

Trigger: User scrolls page · Frequency: Once per threshold per session

Parameter Type Example Notes
scroll_percentage integer 25 Milestones: 25 · 50 · 75 · 100
time_to_scroll integer 12 Seconds from page load to milestone
content_id string "Getting Started with GA4" Post title from window.TNK_PAGE.name

engagement_time

Fires on tab close or navigation away — total active reading time excluding background tab time

Trigger: beforeunload event · Threshold: Only if > 10 seconds active time

Parameter Type Example Notes
engagement_duration_seconds integer 42 Active reading time (excludes background time via Page Visibility API)
content_id string "Getting Started with GA4" Post title
content_category string "Analytics" Category from window.TNK_PAGE.category

code_copy

Fires when user clicks "Copy" button on code blocks in blog posts

Trigger: User clicks copy button · Frequency: Once per code block per session

Parameter Type Example Notes
code_language string "javascript" Detected from class attribute on <code> element (e.g., class="language-javascript")
code_lines integer 7 Number of non-empty lines in copied snippet
snippet_index integer 0 Zero-indexed position of code block on page
content_id string "Getting Started with GA4" Post title

Web Vitals — Frente 3

Core Web Vitals tracking: LCP (Largest Contentful Paint), INP (Interaction to Next Paint), CLS (Cumulative Layout Shift)

LCP — Largest Contentful Paint

Measures when the largest content element becomes visible to the user

Trigger: Page fully loaded · Frequency: Once per session

Threshold Rating Definition
≤ 2.5 seconds good Excellent user experience
2.5 — 4.0 seconds needs_improvement Acceptable but could be better
> 4.0 seconds poor Poor user experience — needs optimization

INP — Interaction to Next Paint

Measures how quickly a page responds to user interactions (clicks, taps, keyboard input)

Trigger: After user interaction · Frequency: Multiple times per session

Threshold Rating Definition
≤ 200 ms good Responsive and interactive
200 — 500 ms needs_improvement Acceptable response time
> 500 ms poor Slow interactions — frustrating for users

CLS — Cumulative Layout Shift

Measures visual stability — how much the page layout shifts during loading and interaction

Trigger: Layout shifts occur · Frequency: Continuous during page interactions

Threshold Rating Definition
≤ 0.1 good Minimal layout shifts — stable page
0.1 — 0.25 needs_improvement Some unexpected shifts
> 0.25 poor Significant shifts — poor user experience

Note: CLS is unitless (0–1 scale). Each 1 is a shift of 100% of viewport. A shift of 0.05 means 5% of viewport height shifted unexpectedly.

Copied!

GTM & GA4 Setup

Naming conventions and configuration reference for GTM-KW97DTMV · G-25V933JKJD

GTM Container
GTM-KW97DTMV
GTM Account
tnk-project · 6343762712
GA4 Measurement ID
G-25V933JKJD
GA4 Stream
tnk-analytics-design-website · 13893341764

Google Tag Manager

Variables, Triggers & Tags — exact names as configured in the container

Variables (27 Data Layer Variables)

# Variable Name Data Layer Variable Name Used In Event(s)
page_view
01dlv - page_namepage_namepage_view
02dlv - page_categorypage_categorypage_view
03dlv - page_typepage_typepage_view
04dlv - content_groupcontent_grouppage_view
05dlv - page_authorpage_authorpage_view
select_content
06dlv - content_typecontent_typeselect_content
07dlv - content_idcontent_idselect_content · post_engagement
08dlv - content_namecontent_nameselect_content · post_engagement
09dlv - item_list_nameitem_list_nameselect_content
10dlv - destination_urldestination_urlselect_content
generate_lead
11dlv - form_nameform_namegenerate_lead
12dlv - form_idform_idgenerate_lead
13dlv - subjectsubjectgenerate_lead
14dlv - budgetbudgetgenerate_lead
15dlv - message_word_countmessage_word_countgenerate_lead
16dlv - message_char_countmessage_char_countgenerate_lead
17dlv - message_filledmessage_filledgenerate_lead
18dlv - email_sha256email_sha256generate_lead
orbit_interaction
19dlv - orbit_pauseorbit_pauseorbit_interaction
20dlv - skill_hoverskill_hoverorbit_interaction
search
21dlv - search_termsearch_termsearch
22dlv - search_results_countsearch_results_countsearch
23dlv - search_has_resultssearch_has_resultssearch
24dlv - search_term_lengthsearch_term_lengthsearch
25dlv - search_sectionsearch_sectionsearch
26dlv - search_active_filtersearch_active_filtersearch
post_engagement
27dlv - actionactionpost_engagement

Triggers (7 triggers)

# Trigger Name Type Event Name / Fires On
01All PagesPage View – Window LoadedAll Pages
02CE - page_viewCustom Eventpage_view
03CE - select_contentCustom Eventselect_content
04CE - generate_leadCustom Eventgenerate_lead
05CE - orbit_interactionCustom Eventorbit_interaction
06CE - searchCustom Eventsearch
07CE - post_engagementCustom Eventpost_engagement

Tags (7 tags)

# Tag Name Tag Type GA4 Event Name Trigger Key Parameters / Notes
01 GA4 - Configuration Google Tag — All Pages send_page_view: false · Tag ID: G-25V933JKJD
02 GA4 - page_view GA4 Event page_view CE - page_view page_name · page_category · page_type · content_group · page_author
03 GA4 - select_content GA4 Event select_content CE - select_content content_type · content_id · content_name · item_list_name · destination_url
04 GA4 - generate_lead GA4 Event generate_lead CE - generate_lead form_name · form_id · subject · budget · message_word_count · message_char_count · message_filled · email_sha256
05 GA4 - orbit_interaction GA4 Event orbit_interaction CE - orbit_interaction orbit_pause · skill_hover
06 GA4 - search GA4 Event search CE - search search_term · search_results_count · search_has_results · search_term_length · search_section · search_active_filter
07 GA4 - post_engagement GA4 Event post_engagement CE - post_engagement content_id · content_name · action

Google Analytics 4

Custom Dimensions, Metrics & Conversions — Admin → Data Display

Custom Dimensions (22 event-scoped)

# Display Name Event Parameter Scope
Page
01Page Namepage_nameEvent
02Page Categorypage_categoryEvent
03Page Typepage_typeEvent
04Content Groupcontent_groupEvent
05Page Authorpage_authorEvent
Navigation / Clicks
06Content Typecontent_typeEvent
07Content IDcontent_idEvent
08Content Namecontent_nameEvent
09Item List Nameitem_list_nameEvent
10Destination URLdestination_urlEvent
Lead Form
11Form Nameform_nameEvent
12Form IDform_idEvent
13SubjectsubjectEvent
14BudgetbudgetEvent
15Message Filledmessage_filledEvent
16Email SHA-256email_sha256Event
Skills / Orbit
17Orbit Pauseorbit_pauseEvent
18Skill Hoverskill_hoverEvent
Search
19Search Has Resultssearch_has_resultsEvent
20Search Sectionsearch_sectionEvent
21Search Active Filtersearch_active_filterEvent
Post Engagement
22Engagement ActionactionEvent

Custom Metrics (4 event-scoped)

# Display Name Event Parameter Unit
01Message Word Countmessage_word_countStandard (integer)
02Message Char Countmessage_char_countStandard (integer)
03Search Results Countsearch_results_countStandard (integer)
04Search Term Lengthsearch_term_lengthStandard (integer)

Conversions

Conversion Event
generate_lead
Admin → Data Display → Events → toggle Mark as conversion
Or: Admin → Conversions → New Conversion Event → type generate_lead

Version History

Changelog — every major update to this measurement plan

v5.4 2026-09-08 Core Web Vitals

Implemented Core Web Vitals tracking to monitor real user experience metrics. Automatically captures LCP (Largest Contentful Paint), INP (Interaction to Next Paint), and CLS (Cumulative Layout Shift) on all pages with automatic performance rating classification.

  • New event: web_vitals — Tracks Core Web Vitals: LCP, INP, CLS with automatic performance ratings
  • New parameters: metric_name (LCP/INP/CLS), metric_value (ms or unitless), metric_rating (good/needs_improvement/poor)
  • Performance thresholds: LCP (good ≤2.5s), INP (good ≤200ms), CLS (good ≤0.1) — follows Core Web Vitals official standards
  • Loaded on all pages in <head> with web-vitals library (v3.5.2 via CDN)
  • GTM changes: 1 new GA4 event tag for web_vitals in container GTM-KW97DTMV — all 3 metrics dispatched as separate events with metric_name parameter
v5.3 2026-09-08 Engagement & Interactivity

Implemented comprehensive engagement tracking for blog posts. Captures scroll behavior, active reading time, and code snippet interactions. Includes automatic injection of copy buttons on all code blocks with language detection and line counting.

  • New event: scroll_depth — Tracks scroll milestones (25%, 50%, 75%, 100%) with time-to-scroll metric
  • New event: engagement_time — Measures active reading time, excludes tab background visibility
  • New event: code_copy — Tracks code snippet copies with language and line count
  • New tracking script: /js/engagement-tracking.js — Auto-injects copy buttons, detects code language from class
  • New parameters: scroll_percentage, time_to_scroll, engagement_duration_seconds, code_language, code_lines, snippet_index
  • GTM changes: 3 new GA4 event tags (scroll_depth, engagement_time, code_copy) in container GTM-KW97DTMV
  • Applied to all 11 blog posts
v5.2 2026-09-08 UTM & Outbound Tracking

Added new event types to close the UTM tracking loop and capture outbound link engagement. Implemented automatic detection and tracking of external links, plus specific resource download tracking for Google Sheets templates and other downloadable assets.

  • New event: resource_download — Tracks clicks to downloadable resources (Google Sheets UTM generator template, etc.)
  • New event: outbound_click — Automatically detects and tracks all external links to social profiles, resources, and external sites
  • New parameters: destination_domain, template_type added to tab2_parameters.csv
  • New tracking scripts: /js/outbound-tracking.js (auto-detection), /js/resource-tracking.js (resource downloads)
  • Updated UTM post: blog/utms-importacion-campanas-ga4.html now has resource_download tracking on the Google Sheets template link
  • GTM changes: 2 new GA4 event tags for resource_download and outbound_click in container GTM-KW97DTMV
v5.1 2026-09-01 New blog post

Added new blog post "UTMs y Importación de Campañas en GA4" to tracking coverage. New page instrumented with page_view, new blog card tracked via select_content in the blog listing, full post_engagement coverage (likes & comments via Supabase), and a new outbound template CTA link inside the article body.

  • New page blog/utms-importacion-campanas-ga4.html added to page_view tracking
  • New blog_card select_content entry for the UTM/GA4 post in the blog listing
  • post_engagement (like/unlike/comment) instrumented with slug utms_importacion_campanas_ga4
  • New external_link content_type value on select_content — first use, for the "Hacer una copia de la plantilla" outbound Google Sheets CTA in the article body
  • Pages instrumented count updated: 16 → 17 pages (10 → 11 with engagement)
v5.0 2026-03-24 Domain update

Updated all site URL references from the Vercel staging domain to the new custom domain tnkproject.com. No tracking changes — documentation update only.

  • Site URL updated: https://tnk-project.vercel.app/ → https://tnkproject.com/
  • GA4 Stream URL updated to match new domain
v4.1 2026-03-17 New blog post

Added new blog post "Analytics Documentation That Never Goes Stale" to tracking coverage. New page instrumented with page_view, new blog card tracked via select_content in the blog listing, and full post_engagement coverage (likes & comments via Supabase).

  • New page blog/analytics-doc-automation.html added to page_view tracking
  • New blog_card select_content entry for the doc-automation post in the blog listing
  • post_engagement (like/unlike/comment) instrumented with slug analytics_doc_automation
  • Pages instrumented count updated: 11 → 12 pages (7 → 8 with engagement)
v4.2 2026-03-17 Complete page inventory

Completed the page_view tab to include all 14 pages currently live on the site. Previously only 5 pages were documented. Also fixed broken screenshot references from v4.1 (pv_blog_doc_automation, sc_blog_card_doc_auto) and added the missing page_view for Portfolio Security Audit.

  • Added 8 missing pages to page_view tab: TNK Portfolio Web, Design Principles for Data Products, Beautiful Dashboards, Building with Claude Code, DataLayer Medición Robusta, Analytics-First Workflow, Portfolio Security Audit, and fixed Analytics Doc Automation screenshot
  • Fixed broken image references from v4.1 (pv_blog_doc_automation.png, sc_blog_card_doc_auto.png)
  • Pages instrumented count updated: 12 → 14 pages
  • Capture script updated to include all new pages
v4.0 2026-03-12 GTM & GA4 setup

Added GTM & GA4 Setup reference tab documenting the exact naming conventions for all GTM objects and GA4 configuration items. GTM container GTM-KW97DTMV deployed to all 13 site pages. GA4 property G-25V933JKJD connected.

  • New tab 09 — GTM & GA4 Setup added with full naming convention tables
  • 27 GTM Data Layer Variables documented (dlv - * naming pattern)
  • 7 GTM Triggers documented (CE - * naming pattern for custom events)
  • 7 GTM Tags documented (GA4 - * naming pattern)
  • 22 GA4 Custom Dimensions + 4 Custom Metrics registered
  • generate_lead marked as GA4 conversion
  • GTM snippets added to all 13 HTML pages (head + noscript body)
  • Intro tab updated with real GTM/GA4 IDs and stream details
  • Archive: measurement_plan_v3.html
v3.0 2026-03-11 Schema refactor

Unified post engagement tracking into a single post_engagement event. Standardised all content_id values across events to use underscores instead of hyphens.

  • Replaced blog_like + blog_comment with single post_engagement event
  • action parameter now carries like | unlike | comment
  • Removed comment_length parameter — no longer sent
  • All content_id values across select_content and post_engagement now use _ separators (e.g. beautiful_dashboards)
  • post_engagement tab rebuilt to match standard event-block structure with #NN index, param-tags, code-block, screenshots
  • Updated all 7 blog HTML files to push post_engagement with underscore slugs
  • Archive: measurement_plan_v2.html
v2.0 2026-03-11 Post engagement

Added post-level engagement features to all 7 blog post pages: likes (heart button with toggle) and comments (form + listing). Backed by Supabase with Row-Level Security. Two new GA4 events, two new parameters.

  • 2 new events: blog_like, blog_comment
  • 2 new parameters: action (like|unlike), comment_length
  • Supabase backend: tables post_likes and post_comments
  • Per-browser like deduplication via localStorage["tnk_browser_id"] (UUID)
  • New tab 08 — post_engagement added to this document
  • Archive: measurement_plan_v1.html
v1.0 2026-03-10 Initial release

First complete measurement plan for the TNK Designs portfolio. Covers all 5 events with full parameter documentation, dataLayer push examples, and per-row screenshots with element highlights.

  • 5 events documented: page_view, select_content, generate_lead, orbit_interaction, search
  • 21 shared parameters across events
  • 29 select_content interactions documented (nav, hero, cards, footer, blog listing, filters, projects, contact)
  • 6 page_view rows (one per unique page_category + page_type combination)
  • 70+ automated screenshots via Puppeteer with red-box element highlights
  • 7 CSV exports for Google Sheets import
  • Archive: measurement_plan_v1.html

Versioning rules

A new version is created for every major update: new event added, existing event removed or renamed, new parameter added/removed, tracking approach changed. Minor fixes (typos, broken links, screenshot refreshes) do not increment the version. Before each version bump, the current file is archived to archive/measurement_plan_vN.html.