This guide provides a comprehensive, step-by-step process for integrating Tinybird analytics with a Ghost blog installed via Ghost-CLI on Ubuntu. While Ghost's official Tinybird integration is currently only available for Docker installations, this guide creates a custom solution that achieves the same functionality for Ghost-CLI installations.

Ghost CMS offers built-in analytics for membership and newsletter metrics, but lacks native website traffic analytics for Ghost-CLI installations. Tinybird is a real-time analytics platform that Ghost has partnered with for Docker deployments.

This guide bridges that gap for Ghost-CLI users by creating a custom proxy service that forwards analytics data from your Ghost blog to Tinybird.

What This Integration Provides

  • Privacy-friendly analytics: No third-party cookies
  • Real-time data collection: Instant pageview tracking
  • Full data ownership: All data stored in your Tinybird workspace
  • SQL access: Query your analytics data with SQL
  • Scalable solution: Handles high-traffic websites efficiently

Prerequisites

On Your Ubuntu Server

  • Ghost installed via Ghost-CLI (not Docker)
  • Node.js and npm installed
  • Nginx as reverse proxy
  • Root or sudo access
  • Ghost running on the default port 2368

On Your Local Machine

  • Web browser for Tinybird setup
  • SSH client (Terminal, PowerShell, or PuTTY)
  • Text editor for saving credentials

Part 1: Set Up Tinybird Account [Local Machine - Browser]

Step 1: Create Tinybird Account

  1. Navigate to https://www.tinybird.co
  2. Sign up for a free account
  3. Verify your email address

Step 2: Create Workspace

  1. When prompted to create a workspace, choose a name (e.g., "ghost_analytics")
  2. Important: Select "Tinybird Classic" (not Tinybird Forward)
  3. Choose your region (note this for later - e.g., "us-east-1")
  4. For "day-to-day work", select any option (e.g., "Data Engineering")
  5. Click "Start"

Step 3: Create the Analytics Data Source

  1. In the left sidebar, click "Data Sources"
  2. Click "Create Data Source" or "+"
  3. Choose "Write schema"
  4. Name it exactly: analytics_events
  5. In the code editor, paste:

sql

SCHEMA >
    `timestamp` DateTime `json:$.timestamp`,
    `event` String `json:$.event`,
    `url` String `json:$.url`,
    `referrer` String `json:$.referrer`,
    `user_agent` String `json:$.user_agent`,
    `title` String `json:$.title`,
    `path` String `json:$.path`,
    `target` Nullable(String) `json:$.target`,
    `text` Nullable(String) `json:$.text`,
    `duration` Nullable(Int32) `json:$.duration`

ENGINE "MergeTree"
ENGINE_SORTING_KEY "timestamp"
ENGINE_TTL ""
ENGINE_PARTITION_KEY ""
  1. Click "Next" then "Create Data Source"

Step 4: Gather Credentials

  1. Get API URL:
    • Based on your region selection:
    • US East (us-east-1): https://api.us-east.aws.tinybird.co
    • EU: https://api.eu.tinybird.co
    • Default: https://api.tinybird.co
  2. Get Tokens:
    • Go to "Tokens" in the left sidebar
    • Copy the existing admin token
    • Click "Create Token"
    • Name it "Ghost Tracker Token"
    • Add Data Source scope for analytics_events with "Append" permission
    • Copy this token
  3. Get Workspace ID:
    • Click "Settings" in the left sidebar
    • Copy the Workspace ID

Save these four values in a text file:

API URL: https://api.us-east.aws.tinybird.co (your actual URL)
Admin Token: p.ey... (your admin token)
Tracker Token: p.ey... (your tracker token)
Workspace ID: ws_... (your workspace ID)

Part 2: Configure Ghost Server [Ubuntu Server - SSH]

Step 1: Connect to Your Server

bash

ssh root@YOUR_SERVER_IP

Step 2: Configure Ghost with Tinybird

Navigate to your Ghost installation:

bash

cd /var/www/ghost
# Or: cd /var/www/yourdomain.com

Add Tinybird configuration (replace with your actual values):

bash

ghost config set analytics:tinybird:enabled true
ghost config set analytics:tinybird:apiUrl "YOUR_API_URL"
ghost config set analytics:tinybird:adminToken "YOUR_ADMIN_TOKEN"
ghost config set analytics:tinybird:workspaceId "YOUR_WORKSPACE_ID"
ghost config set analytics:tinybird:trackerToken "YOUR_TRACKER_TOKEN"

ghost restart

Part 3: Create Analytics Proxy Service [Ubuntu Server - SSH]

Step 1: Set Up Project Directory

bash

sudo mkdir -p /var/www/ghost-analytics
cd /var/www/ghost-analytics

Step 2: Create Package Configuration

bash

sudo nano package.json

Paste exactly:

json

{
  "name": "ghost-analytics-proxy",
  "version": "1.0.0",
  "main": "server.js",
  "dependencies": {
    "express": "^4.18.0",
    "http-proxy-middleware": "^2.0.0",
    "node-fetch": "^3.3.0"
  }
}

Save with Ctrl+X, Y, Enter.

Step 3: Install Dependencies

bash

sudo npm install

Step 4: Create the Proxy Server

bash

sudo nano server.js

Paste:

javascript

const express = require('express');
const app = express();

const TINYBIRD_API_URL = process.env.TINYBIRD_API_URL;
const TINYBIRD_TRACKER_TOKEN = process.env.TINYBIRD_TRACKER_TOKEN;
const PORT = process.env.PORT || 3001;

app.use(express.json());

// Health check
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'healthy' });
});

// Proxy analytics to Tinybird
app.post('/analytics', async (req, res) => {
  try {
    const fetch = (await import('node-fetch')).default;
    const url = `${TINYBIRD_API_URL}/v0/events?name=analytics_events`;
    
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${TINYBIRD_TRACKER_TOKEN}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(req.body)
    });
    
    const text = await response.text();
    console.log('Tinybird response:', response.status);
    
    res.status(200).json({ success: true });
  } catch (error) {
    console.error('Proxy error:', error);
    res.status(200).json({ success: true });
  }
});

app.listen(PORT, '127.0.0.1', () => {
  console.log(`Analytics proxy running on port ${PORT}`);
});

Save the file.

Step 5: Create Systemd Service

bash

sudo nano /etc/systemd/system/ghost-analytics.service

Paste (replace YOUR_API_URL and YOUR_TRACKER_TOKEN with actual values):

ini

[Unit]
Description=Ghost Analytics Proxy for Tinybird
After=network.target

[Service]
Type=simple
WorkingDirectory=/var/www/ghost-analytics
Environment="NODE_ENV=production"
Environment="PORT=3001"
Environment="TINYBIRD_API_URL=YOUR_API_URL"
Environment="TINYBIRD_TRACKER_TOKEN=YOUR_TRACKER_TOKEN"
ExecStart=/usr/bin/node server.js
Restart=always
User=ghost
Group=ghost

[Install]
WantedBy=multi-user.target

Save the file.

Step 6: Start the Service

bash

sudo chown -R ghost:ghost /var/www/ghost-analytics
sudo systemctl daemon-reload
sudo systemctl enable ghost-analytics
sudo systemctl start ghost-analytics
sudo systemctl status ghost-analytics

You should see "Active: active (running)".


Part 4: Configure Nginx [Ubuntu Server - SSH]

Step 1: Edit Nginx Configuration

Find your site's SSL configuration:

bash

ls /etc/nginx/sites-available/
sudo nano /etc/nginx/sites-available/YOUR_DOMAIN-ssl.conf

Step 2: Add Analytics Location Block

Inside the server block (after the location / block), add:

nginx

    location /analytics {
        proxy_pass http://127.0.0.1:3001/analytics;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

Step 3: Test and Reload

bash

sudo nginx -t
sudo systemctl reload nginx

Part 5: Add Tracking Script to Ghost Theme [Ubuntu Server - SSH]

Step 1: Navigate to Your Theme

bash

cd /var/www/ghost/content/themes/YOUR_THEME_NAME
sudo nano default.hbs

Step 2: Add Tracking Script

Find the </body> tag and add this directly before it:

html

<script>
(function() {
  function sendEvent(eventType, properties) {
    const event = {
      timestamp: new Date().toISOString(),
      event: eventType,
      url: window.location.href,
      referrer: document.referrer,
      user_agent: navigator.userAgent,
      ...properties
    };

    fetch('/analytics', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify(event)
    }).catch(err => console.error('Analytics error:', err));
  }

  sendEvent('pageview', {
    title: document.title,
    path: window.location.pathname
  });
})();
</script>
</body>

Save the file.

Step 3: Restart Ghost

bash

cd /var/www/ghost
ghost restart

Part 6: Verification and Testing

Step 1: Test the Analytics Endpoint

From your server:

bash

curl -X POST https://YOUR_DOMAIN/analytics \
  -H "Content-Type: application/json" \
  -d '{"event": "test", "timestamp": "'$(date -Iseconds)'"}'

Step 2: Check Browser Network Tab

  1. Visit your blog
  2. Open Developer Tools (F12)
  3. Go to Network tab
  4. Filter by "Fetch/XHR"
  5. Look for POST requests to /analytics - should return 200 status

Step 3: Verify Data in Tinybird

  1. Go to Tinybird dashboard
  2. Click "Data Sources"
  3. Click on analytics_events
  4. You should see incoming events

Troubleshooting Guide

Issue: Wrong API Region Error

Symptom: 404 error with message about wrong region

Solution: Update API URL in systemd service:

bash

sudo nano /etc/systemd/system/ghost-analytics.service
# Update TINYBIRD_API_URL with correct regional URL
sudo systemctl daemon-reload
sudo systemctl restart ghost-analytics

Issue: No Analytics Requests in Browser

Symptom: No /analytics requests in Network tab

Solution: Verify tracking script is present:

bash

curl -s https://YOUR_DOMAIN | grep -A 5 "sendEvent"

Issue: 404 Error on Analytics Endpoint

Symptom: /analytics returns 404

Solution: Check Nginx configuration:

bash

grep -A 5 "location /analytics" /etc/nginx/sites-available/*-ssl.conf
sudo nginx -t
sudo systemctl reload nginx

Issue: Service Not Starting

Symptom: ghost-analytics service fails

Solution: Check logs and permissions:

bash

sudo journalctl -u ghost-analytics -n 50
sudo chown -R ghost:ghost /var/www/ghost-analytics

Maintenance

View Service Status

bash

sudo systemctl status ghost-analytics

View Service Logs

bash

sudo journalctl -u ghost-analytics -f

Restart Service After Changes

bash

sudo systemctl restart ghost-analytics

Update Node Dependencies

bash

cd /var/www/ghost-analytics
sudo npm update
sudo systemctl restart ghost-analytics

Viewing Your Analytics

Analytics data is accessible through Tinybird's interface:

  1. Basic Queries: Use Tinybird's SQL interface
  2. Create Pipes: Build reusable queries and API endpoints
  3. Export Data: Download or stream to other services
  4. Build Dashboards: Use Tinybird's visualization tools or connect to external BI tools

Example query for daily pageviews:

sql

SELECT 
  toDate(timestamp) as date,
  count() as pageviews,
  count(DISTINCT user_agent) as unique_visitors
FROM analytics_events
WHERE event = 'pageview'
GROUP BY date
ORDER BY date DESC

Important Notes

  1. Not Official Integration: This is a custom solution for Ghost-CLI installations
  2. Data Location: Analytics data is viewed in Tinybird, not Ghost Admin
  3. Privacy Compliant: No third-party cookies are used
  4. Scalable: Tinybird handles millions of events efficiently
  5. Cost: Tinybird's free tier includes 10GB storage and 1000 API requests/day

Conclusion

You now have a complete, privacy-friendly analytics system for your Ghost blog. While the data doesn't appear in Ghost Admin (that's only for Docker installations), you have full access to your analytics through Tinybird's powerful interface with SQL querying capabilities.

Share this post