Guides/How to build a multi-site analytics dashboard

How to build a multi-site analytics dashboard

One dashboard. Every project. Zero cookies.

Updated March 2026

Sutrena is the web runtime for AI agents. When you run multiple sites -- a marketing site, a blog, a SaaS app, hosted landing pages -- you need a single place to see how all of them are performing. This guide walks you through creating analytics sites for each project, adding the tracking script, and combining everything into one multi-source tabbed dashboard. Each analytics site is privacy-first (no cookies, no PII), and the dashboard updates in real time with 30-second auto-refresh. You can mix Sutrena-hosted pages (auto-tracked server-side) with external sites (one script tag each).

1. Create a folder to organize everything

Start with a folder. Folders group related analytics sites, dashboards, and forms. This keeps the combined dashboard and all its data sources in one place. Folders are unlimited on every plan.

curl -X POST https://sutrena.com/api/folders \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Analytics Command Center"}'

# Response:
# {
#   "id": "folder_abc123",
#   "name": "Analytics Command Center"
# }

2. Create an analytics site for each project

Create one analytics site per project. For Sutrena-hosted pages, pass subdomainId to enable automatic server-side tracking (no client JavaScript needed). For external sites, omit subdomainId and use the script tag from step 3. Place each site in the folder you just created.

# External site (marketing site)
curl -X POST https://sutrena.com/api/analytics/sites \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Marketing Site", "domain": "example.com", "folderId": "folder_abc123"}'

# Sutrena-hosted pages (auto-tracked, no script needed)
curl -X POST https://sutrena.com/api/analytics/sites \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Hosted Pages", "subdomainId": "sub_xyz", "folderId": "folder_abc123"}'

# Another external site (blog)
curl -X POST https://sutrena.com/api/analytics/sites \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Blog", "domain": "blog.example.com", "folderId": "folder_abc123"}'

# Save the returned IDs -- you need them for the dashboard sources

3. Add the tracking script to external sites

For each external site, add one script tag. The script is ~1.2 KB, loads asynchronously, uses no cookies, and supports single-page apps. Sutrena-hosted pages skip this step -- they are tracked server-side automatically.

<!-- Add to <head> or before </body> on each external site -->
<!-- Marketing site -->
<script defer data-site="sa_marketing123" src="https://sutrena.com/a.js"></script>

<!-- Blog -->
<script defer data-site="sa_blog456" src="https://sutrena.com/a.js"></script>

<!-- Works with any framework: Astro, Next.js, Hugo, plain HTML -->

4. Build the multi-source dashboard

Create a dashboard with a sources map. Each source points to an analytics site by ID. Widgets reference a source by name. Use tabs to organize views: an overview with metric cards and traffic trends, a visitor profile with device/country breakdowns, and a live today tab for real-time monitoring.

curl -X POST https://sutrena.com/api/dashboards \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Analytics Command Center",
    "folderId": "folder_abc123",
    "isPublic": false,
    "dsl": {
      "version": 1,
      "sources": {
        "marketing": {"type": "analytics", "analyticsSiteId": "site_marketing_id"},
        "blog": {"type": "analytics", "analyticsSiteId": "site_blog_id"},
        "hosted": {"type": "analytics", "analyticsSiteId": "site_hosted_id"}
      },
      "tabs": [
        {
          "label": "Overview (30d)",
          "widgets": [
            {"type": "metric_card", "title": "Marketing Views", "source": "marketing", "metric": "page_views", "period": "30d", "compare": true},
            {"type": "metric_card", "title": "Blog Views", "source": "blog", "metric": "page_views", "period": "30d", "compare": true},
            {"type": "metric_card", "title": "Hosted Views", "source": "hosted", "metric": "page_views", "period": "30d", "compare": true},
            {"type": "line_chart", "title": "Daily Traffic", "source": "marketing", "metric": "page_views", "period": "30d", "groupBy": "$submitted_at:day"}
          ]
        },
        {
          "label": "Visitor Profile",
          "widgets": [
            {"type": "pie_chart", "title": "Devices", "source": "marketing", "metric": "page_views", "breakdownBy": "device", "period": "30d", "groupBy": "device"},
            {"type": "bar_chart", "title": "Countries", "source": "marketing", "metric": "page_views", "breakdownBy": "country", "period": "30d", "groupBy": "country"},
            {"type": "pie_chart", "title": "Browsers", "source": "marketing", "metric": "page_views", "breakdownBy": "browser", "period": "30d", "groupBy": "browser"}
          ]
        },
        {
          "label": "Today",
          "widgets": [
            {"type": "metric_card", "title": "Marketing Today", "source": "marketing", "metric": "page_views", "period": "today"},
            {"type": "metric_card", "title": "Blog Today", "source": "blog", "metric": "page_views", "period": "today"},
            {"type": "metric_card", "title": "Hosted Today", "source": "hosted", "metric": "page_views", "period": "today"},
            {"type": "bar_chart", "title": "Top Pages", "source": "marketing", "metric": "page_views", "breakdownBy": "url", "period": "today", "groupBy": "url"}
          ]
        }
      ]
    }
  }'

5. Add period comparison to spot trends

Set compare: true on metric cards to see the change from the previous period. A 30d metric card compares against the 30 days before that. Useful for catching traffic drops or growth spikes across all your sites at a glance.

# The compare field on metric_card widgets shows the trend arrow
# Example response when querying analytics:
# {
#   "total": 4823,
#   "comparison": {
#     "total": 3912,
#     "changePercent": 23.29
#   }
# }

# You can also query analytics directly for any site:
curl -G https://sutrena.com/api/analytics/query \
  -H "Authorization: Bearer $KEY" \
  --data-urlencode "siteId=site_marketing_id" \
  --data-urlencode "metric=page_views" \
  --data-urlencode "period=30d" \
  --data-urlencode "compare=true"

6. Use MCP tools for AI-powered setup

If you use Claude Code or another MCP client, the entire workflow can be done through MCP tools. Create analytics sites with sutrena_create_analytics_site, build the dashboard with sutrena_create_dashboard, and query data with sutrena_analytics_query. The multi-site-analytics workflow preset automates all steps.

# Via MCP (Claude Code, Cursor, etc.):
# 1. sutrena_create_folder → folder ID
# 2. sutrena_create_analytics_site (repeat for each site) → site IDs
# 3. sutrena_create_dashboard with sources map + tabs → dashboard URL
# 4. sutrena_analytics_query to check data is flowing

# Or query data directly:
# sutrena_analytics_query with siteId and metric

FAQ

How many analytics sites can I track in one dashboard?

A multi-source dashboard supports up to 10 sources. Each source can be an analytics site or a form. You can combine both types in one dashboard. Analytics sites count toward your project limit (Free: 5, Pro: 100, Scale: unlimited).

Does each site consume separate event quota?

All analytics sites share your monthly event quota. Free: 5K events/mo, Pro: 1M, Scale: unlimited. Monitor usage via GET /api/account/usage or the sutrena_check_usage MCP tool.

Can I mix form data and analytics in the same dashboard?

Yes. The sources map accepts both form and analytics types. Use {"type": "form", "formId": "..."} alongside {"type": "analytics", "analyticsSiteId": "..."}. Form widgets use value/groupBy syntax while analytics widgets use metric/breakdownBy.

How do tabs work?

Tabs are an alternative to a flat widgets array. Set tabs instead of widgets in the DSL (they are mutually exclusive). Each tab has a label and its own widgets array. Maximum 10 tabs, 50 total widgets across all tabs. The active tab persists across page refreshes via URL hash.

Can I make the dashboard public?

Set isPublic: true when creating or updating the dashboard. Public dashboards are accessible to anyone with the URL. Private dashboards (the default) require authentication. Share public dashboard URLs with your team or embed them in internal tools.

What is Sutrena?

Sutrena is the web runtime for AI agents. Forms, Pages, Dashboards, Analytics, Webhooks, Automations, Emails — all through 75 MCP tools and one REST API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Use any one feature or all of them together.

Pages

Deploy HTML instantly

Forms

Collect structured data

Dashboards

Visualize with 7 widget types

Analytics

Privacy-first, no cookies

Webhooks

Slack, Discord, Telegram

Get started in two API calls

1. Get a trial key (no auth, no signup)

curl -X POST https://sutrena.com/api/trial

2. Create anything — a page, form, dashboard, or analytics site

# Create a form with a dashboard
curl -X POST https://sutrena.com/api/forms \
  -H "Authorization: Bearer st_trial_xxx" \
  -H "Content-Type: application/json" \
  -d '{"workflowId": "waitlist", "createDashboard": true}'

# Or deploy a page
curl -X POST https://sutrena.com/api/pages \
  -H "Authorization: Bearer st_trial_xxx" \
  -H "Content-Type: application/json" \
  -d '{"slug": "index", "title": "My Site", "html": "<h1>Live</h1>"}'

Ready to build?

Get a trial API key instantly with no signup, or create an account for the full experience.

Multi-site analytics dashboard — combine traffic from all your sites | Sutrena | Sutrena