算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
analytics-tracking【设计与创意】Designs and implements website analytics tracking with Google Analytics 4 and Google Tag Manager: a written tracking plan, event and parameter names that pass GA4's rules, gtag.js or data-layer code, key events, consent mode, UTM conventions, and a verification pass. Use when someone says "set up GA4", "add conversion tracking", "track this form or b…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Tracking is finished when a named person can answer a business question from a report, not when a tag fires. This skill takes a site from "we have GA4 installed" to a short tracking plan, code that sends each event exactly once with valid names, the Admin settings that make the data usable, and proof that it works. Everything here follows Google's current documentation for GA4, the Google tag and Tag Manager; Universal Analytics concepts (categories, actions, labels, goals, anonymize_ip) do not apply.
Ask: which decisions the data should inform, which actions count as success (lead, signup, purchase), which regions the visitors come from (consent), and who is allowed to publish the Tag Manager container. Then look in the code:
grep -rnE "gtag\(|dataLayer\.push|googletagmanager\.com|GTM-[A-Z0-9]{4,}|G-[A-Z0-9]{8,}|@next/third-parties" \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" --include="*.html" \
--exclude-dir=node_modules --exclude-dir=.next .
Choose one delivery path and keep to it. If a GTM- container is on the page, send events through the data layer and configure tags in Tag Manager; if only the Google tag is present, call gtag() directly. The same event sent through both paths is counted twice.
page_view (page loads and browser-history changes), scroll (once per page at 90% depth), click (outbound links only), view_search_results, video_start / video_progress / video_complete (embedded YouTube), file_download, form_start and form_submit. Do not re-implement these.sign_up and login (method), generate_lead (currency, value, lead_source), search (search_term), view_item, add_to_cart, begin_checkout, add_payment_info, purchase (transaction_id, currency, value, items).cta_click with cta_location: "pricing_hero", not a separate event name per button.Names must pass these limits; GA4 does not log what exceeds them, and nothing in the browser reports an error:
| Item | Rule |
|---|---|
| Event name | Starts with a letter; letters, digits and underscores only; case-sensitive; 40 characters |
| Parameters | 25 per event; name 40 characters; value 100 characters (page_location 1,000, page_referrer 420, page_title 300) |
| User properties | 25 per property; name 24 characters; value 36 characters |
| Reserved | Parameter names starting with _, firebase_, ga_, google_ or gtag.. Do not reuse automatic names (click, scroll, session_start, first_visit, user_engagement, form_submit, file_download) for custom events |
| Per standard property | 30 key events, 50 event-scoped and 25 user-scoped custom dimensions, 50 custom metrics |
Money: value is a number, never a string, and always travels with currency (ISO 4217, "USD"). For purchase, value is the sum of price × quantity and excludes shipping and tax; transaction_id is required and is what keeps a repeated purchase from being counted again.
Create docs/tracking-plan.md with one row per event: event name, the exact moment it fires (a server-confirmed success, not a button press), parameters with example values, whether it is a key event, and which path sends it. Example 1 shows the format. Every later step works from this file.
Google tag with consent defaults. The consent default must run before the tag loads; the order of these blocks is the point.
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
analytics_storage: 'denied',
wait_for_update: 500
});
</script>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-7KQ2M4XW9P"></script>
<script>
gtag('js', new Date());
gtag('config', 'G-7KQ2M4XW9P');
</script>
When the visitor answers the banner, the consent tool calls gtag('consent', 'update', { analytics_storage: 'granted', ... }) with all four types, and repeats that on later pages from the stored choice. Add region: ['ES', 'FR'] to a default to scope it; the most specific region wins. Which defaults to set is the site owner's legal decision, not a technical one. In Tag Manager, use a consent template from the Community Template Gallery (or the consent APIs in a custom template), never a Custom HTML tag.
Events with gtag.js go anywhere below the snippet: gtag('event', 'generate_lead', { currency: 'USD', value: 180, lead_source: 'demo_form' }).
Events with Tag Manager. The page pushes a message that carries an event key; a GA4 Event tag listens for it with a Custom Event trigger and reads the fields through Data Layer Variables. For ecommerce events, clear the previous object first:
dataLayer.push({ ecommerce: null });
dataLayer.push({
event: 'purchase',
ecommerce: {
transaction_id: 'ST-20418',
value: 43.50,
tax: 3.48,
shipping: 4.90,
currency: 'USD',
items: [
{ item_id: 'OOL-100', item_name: 'High Mountain Oolong 100 g', price: 14.50, quantity: 3 }
]
}
});
Single-page apps. Enhanced measurement sends page_view on pushState, popState and replaceState when "Page changes based on browser history events" is ticked (Admin > Data collection and modification > Data streams > the stream > Enhanced measurement > Page views > advanced settings). With Tag Manager, send page_view from a GA4 Event tag on a History Change trigger and leave that option off, or every navigation counts twice. To send page views by hand, set send_page_view: false in config and turn the history option off as well.
Signed-in users. Pass an internal ID with gtag('config', 'G-7KQ2M4XW9P', { user_id: 'u_48211' }): an opaque ID, never an email address.
Server-side events (a webhook confirms payment, a CRM marks a lead qualified) go through the Measurement Protocol: POST https://www.google-analytics.com/mp/collect?measurement_id=...&api_secret=... with a JSON body holding client_id and up to 25 events. Read the browser's client_id and session_id with gtag('get', 'G-7KQ2M4XW9P', 'client_id', callback) and store them with the order. Include session_id and engagement_time_msec in params; without them the event does not count toward session and engagement metrics or show properly in Realtime. The secret is created under Admin > Data collection and modification > Data streams > the stream > Measurement Protocol API secrets and stays in a server environment variable. For EU collection use the host region1.google-analytics.com.
purchase is one by default. Allow up to 24 hours for standard reports.| Parameter | Use |
|---|---|
utm_source | Who sent the visit: newsletter, linkedin, partner-fieldnotes |
utm_medium | Channel type; GA4 maps it to a default channel (table below) |
utm_campaign | The campaign, identical across every platform it runs on |
utm_id | Campaign ID, needed when cost data is imported |
utm_content, utm_term | Creative variant; paid keyword |
Always set source, medium and campaign together. Values are case-sensitive (Email and email become two rows), so use lowercase throughout. Keep UTMs off links between your own pages and never put personal data in them.
utm_medium value | Default channel group |
|---|---|
email | |
cpc, ppc, or anything starting with paid | Paid Search, Paid Social, Paid Shopping, Paid Video or Paid Other, depending on the source |
social | Organic Social |
affiliate | Affiliates |
display, banner, cpm | Display |
referral | Referral |
sms | SMS |
debug_mode: true to the event or config; remove the key afterwards, because setting it to false does not switch it off.Prompt: "Kestrel Payroll's marketing site is Next.js. GA4 is installed with the Google tag. We need demo requests and signups as conversions, and we want to know which company sizes ask for demos."
The plan the agent writes to docs/tracking-plan.md:
| Event | Fires when | Parameters (example) | Key event | Sent by |
|---|---|---|---|---|
| page_view | page load and route change | automatic | no | enhanced measurement |
| file_download | click on a PDF link | automatic | no | enhanced measurement |
| generate_lead | POST /api/demo returns 200 | currency "USD", value 180, lead_source "demo_form", company_size "51-200" | yes | gtag |
| sign_up | account row created | method "email" or "google" | yes | gtag |
| cta_click | click on a primary button | cta_location "pricing_hero", cta_text "Start free trial" | no | gtag |
Custom dimensions to register (event scope): company_size, cta_location, lead_source
Lead value: 180 USD = 6% demo-to-customer rate × 3,000 USD first-year revenue
Verified in DebugView: 2026-10-02
The code:
// app/layout.tsx — loads the Google tag once for every route
import { GoogleAnalytics } from '@next/third-parties/google'
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
<GoogleAnalytics gaId={process.env.NEXT_PUBLIC_GA_ID!} />
</html>
)
}
// app/demo/DemoForm.tsx — fire only after the server accepted the request
'use client'
import { sendGAEvent } from '@next/third-parties/google'
export async function submitDemo(form: { email: string; companySize: string }) {
const res = await fetch('/api/demo', { method: 'POST', body: JSON.stringify(form) })
if (!res.ok) return
sendGAEvent('event', 'generate_lead', {
currency: 'USD',
value: 180,
lead_source: 'demo_form',
company_size: form.companySize, // the email address is never sent
})
}
Then the Admin steps: star generate_lead and sign_up as key events, register the three custom dimensions, set retention to 14 months, confirm "Page changes based on browser history events" is ticked so App Router navigations count as page views.
Prompt: "Saltmarsh Tea runs on a custom storefront with Tag Manager. GA4 shows about 30% more purchases than our order system."
The agent searches the code, finds the purchase push in the order-confirmation page with no transaction_id, and a second GA4 tag firing on the same page from a Page View trigger. Customers who reload the confirmation page, or reopen it from the order email, send the event again. The fix:
purchase once, with transaction_id set to the order number and the ecommerce: null reset before it (the code in step 4).purchase on a Custom Event trigger named purchase, map transaction_id, value, currency and items from Data Layer Variables, and delete the Page View tag.The validation server accepts the same request as the live endpoint, stores nothing, and explains what is wrong. It does not check the secret or the measurement ID.
curl -s -X POST "https://www.google-analytics.com/debug/mp/collect?measurement_id=G-7KQ2M4XW9P&api_secret=$GA_API_SECRET" \
-H "Content-Type: application/json" \
-d '{"client_id":"1837264019.1759312800","validation_behavior":"ENFORCE_RECOMMENDATIONS",
"events":[{"name":"Demo Request","params":{"value":180}}]}'
{
"validationMessages": [ {
"fieldPath": "events",
"description": "Event at index: [0] has invalid name [Demo Request]. Only alphanumeric characters and underscores are allowed.",
"validationCode": "NAME_INVALID"
} ]
}
Renamed to generate_lead with currency, value, session_id and engagement_time_msec, the same request returns an empty validationMessages array. Only then does the agent switch the URL to /mp/collect.
anonymize_ip can be deleted.debug_mode to everyone.