Tinacms Analytics Integrations: Setup Guide | OpsBlu Docs

Tinacms Analytics Integrations: Setup Guide

Integrate GA4, GTM, and Meta Pixel with TinaCMS in Next.js and other React-based frameworks. Covers TinaCMS's Git-backed editing model and visual...

TinaCMS is a Git-backed headless CMS that provides visual editing for React-based sites (primarily Next.js). Content is stored in Markdown/MDX files in your Git repository and queried via TinaCMS's GraphQL API. Since TinaCMS is a frontend editing layer (not a standalone CMS), analytics integration happens in your Next.js/React application.

Integration Architecture

TinaCMS adds editing capabilities to your existing frontend:

  1. Next.js Framework -- Your Next.js application handles all page rendering, script loading, and analytics. TinaCMS provides the editing UI and content API, not the public-facing site.
  2. TinaCMS GraphQL API -- Query content from your Markdown/MDX files via TinaCMS's auto-generated GraphQL schema. Content fields populate your data layer.
  3. Git Repository -- Content changes are committed to Git. CI/CD rebuilds the site with updated content. There is no runtime API in production -- content is pre-rendered at build time.

Available Integrations

Analytics Platforms

Google Analytics 4

  • Next.js app shell integration
  • GTM-based GA4 with TinaCMS content data layer

Tag Management

Google Tag Manager

  • Next.js _document.tsx or layout.tsx
  • SPA route-change tracking

Marketing Pixels

Meta Pixel

  • Via GTM container (recommended)
  • Direct integration in Next.js app shell

Next.js + TinaCMS Example

Build the data layer from TinaCMS GraphQL queries at build time:

// app/posts/[slug]/page.tsx
import { client } from '@/tina/__generated__/client';

export default async function Post({ params }) {
  const { data } = await client.queries.post({
    relativePath: `${params.slug}.mdx`,
  });
  const post = data.post;

  return (
    <>
      <script
        dangerouslySetInnerHTML={{
          __html: `
            window.dataLayer = window.dataLayer || [];
            window.dataLayer.push({
              event: 'virtual_pageview',
              content_type: 'blog_post',
              page_title: ${JSON.stringify(post.title)},
              author: ${JSON.stringify(post.author || '')},
              category: ${JSON.stringify(post.category || '')},
              tags: ${JSON.stringify(post.tags?.join(',') || '')},
              publish_date: '${post.date || ''}'
            });
          `,
        }}
      />
      <article>{/* render with TinaMarkdown */}</article>
    </>
  );
}

export async function generateStaticParams() {
  const { data } = await client.queries.postConnection();
  return data.postConnection.edges.map((edge) => ({
    slug: edge.node._sys.filename,
  }));
}

TinaCMS Content Schema for Analytics

TinaCMS schemas (defined in tina/config.ts) determine what content fields are available for the data layer:

// tina/config.ts (excerpt showing analytics-relevant fields)
export default defineConfig({
  schema: {
    collections: [{
      name: 'post',
      label: 'Blog Posts',
      path: 'content/posts',
      fields: [
        { name: 'title', label: 'Title', type: 'string', isTitle: true },
        { name: 'author', label: 'Author', type: 'string' },
        { name: 'category', label: 'Category', type: 'string',
          options: ['Engineering', 'Design', 'Marketing'] },
        { name: 'tags', label: 'Tags', type: 'string', list: true },
        { name: 'date', label: 'Date', type: 'datetime' },
      ],
    }],
  },
});

Platform Limitations

No platform-level tracking. TinaCMS has no built-in analytics. It is an editing layer, not a hosting or delivery platform. All analytics are your Next.js application's responsibility.

Visual editor tracking pollution. TinaCMS's visual editor loads an iframe with your site for live editing. If tracking scripts fire inside the visual editor, they generate false analytics events. Use an environment check or hostname condition to suppress tracking when window.__tina is present:

// Suppress tracking in TinaCMS visual editor
if (typeof window !== 'undefined' && !window.__tina) {
  // Initialize GTM / fire analytics
}

Static build model. TinaCMS content is typically pre-rendered at build time via generateStaticParams(). Data layer values are baked into the HTML at build time and do not change until the next build. This is ideal for analytics (data layer is always available before GTM fires) but means content updates require a rebuild to reflect in analytics data.

Git-based content. Content changes trigger Git commits and CI/CD rebuilds. There is no instant content update -- analytics data layer values lag behind content edits by the build/deploy time (typically 1-5 minutes).

Performance Considerations

  • SSG performance. TinaCMS sites are statically generated, delivering pre-rendered HTML from a CDN. This provides the best possible performance baseline. Data layer values are in the HTML from the first byte.
  • No runtime API calls. In production, TinaCMS does not make API calls. Content is pre-rendered. This eliminates the API latency that affects other headless CMS platforms.
  • TinaCMS editor bundle. The TinaCMS editing UI adds a significant JavaScript bundle (~200KB+). This only loads in editing mode, not on the published site. Verify your deployment excludes the TinaCMS editor from production builds.
  1. Add GTM to Next.js layout -- app/layout.tsx or _document.tsx
  2. Suppress tracking in visual editor -- Check for window.__tina presence
  3. Build content schema-aware data layer -- Map TinaCMS collection types and fields to data layer variables
  4. Configure GA4 in GTM -- Content groups from TinaCMS categories
  5. Add Meta Pixel via GTM -- Standard engagement tracking

Next Steps

For general integration concepts, see the integrations overview.