How to Extend the Analytics Dashboard with Custom API Endpoints

To extend the analytics dashboard with custom API endpoints, create a TypeScript file under dashboard/src/pages/api/ that exports named HTTP method handlers such as POST or GET, leveraging the existing CORS utilities and Supabase client from davila7/claude-code-templates to handle requests and persist data.

The analytics dashboard in the davila7/claude-code-templates repository is built with Astro and React, utilizing Astro's file-based routing for API endpoints. Custom endpoints follow the architectural patterns established in the existing analytics collection, ensuring compatibility with the dashboard's data ingestion pipeline and frontend components.

Understanding the Dashboard Architecture

The dashboard workspace implements server-side logic through Astro API routes. Any file placed under dashboard/src/pages/api/ automatically becomes a server endpoint, with the route path mirroring the file location. This convention powers existing analytics features such as track-download-supabase.ts and track-command-usage.ts, which handle telemetry ingestion for the template ecosystem.

Key architectural decisions to note:

  • File-based routing eliminates manual route registration
  • Named exports (POST, GET, OPTIONS) define HTTP method handlers
  • Centralized utilities in dashboard/src/lib/api/ handle cross-cutting concerns like CORS and database connections

Creating a Custom API Endpoint

File Location and Naming Conventions

Place new endpoint files under dashboard/src/pages/api/ using descriptive kebab-case names. For example, a metric tracking user engagement might be named track-custom-metric.ts.

Required structure:

  • Path: dashboard/src/pages/api/[endpoint-name].ts
  • Extension: .ts (TypeScript)
  • Export pattern: Named exports for HTTP methods

Implementing the Route Handler

Astro expects handlers to use the APIRoute type from astro. The standard pattern involves parsing request payloads, validating required fields, interacting with the database via Supabase, and returning JSON responses using the shared jsonResponse utility.

// dashboard/src/pages/api/track-custom-metric.ts
import type { APIRoute } from 'astro';
import { jsonResponse, corsResponse } from '../../lib/api/cors';
import { supabase } from '../../lib/api/neon';

export const POST: APIRoute = async ({ request }) => {
  // Parse incoming JSON payload
  const payload = await request.json();

  // Validate required fields against your metric schema
  if (!payload?.event || !payload?.userId) {
    return jsonResponse({ error: 'Missing required fields' }, { status: 400 });
  }

  // Insert record into Supabase
  const { error } = await supabase
    .from('custom_metrics')
    .insert({
      event: payload.event,
      user_id: payload.userId,
      metadata: payload.metadata ?? null,
      created_at: new Date().toISOString(),
    });

  if (error) {
    return jsonResponse({ error: error.message }, { status: 500 });
  }

  return jsonResponse({ ok: true });
};

// Expose OPTIONS endpoint for CORS preflight requests
export const OPTIONS = corsResponse;

Reusing Core Utilities

The repository provides standardized helpers to ensure consistency across endpoints.

CORS Handling

Import corsResponse and jsonResponse from dashboard/src/lib/api/cors.ts. This utility applies consistent CORS headers required for client-side calls from the dashboard frontend.

Database Client

The Supabase client is instantiated in dashboard/src/lib/api/neon.ts. Import this singleton to execute queries against the analytics database without re-initializing connection pools.

Error Handling Pattern

Follow the established pattern seen in track-command-usage.ts: return jsonResponse with appropriate HTTP status codes (400 for validation errors, 500 for database failures, 200 for success).

Integrating with the Frontend

After creating the endpoint, you can surface the data in the dashboard UI.

Creating Service Functions

Add client-side data fetching logic to dashboard/src/lib/collections-api.ts or create a dedicated service file. Use standard fetch calls to your new endpoint:

// dashboard/src/lib/collections-api.ts
export async function fetchCustomMetrics() {
  const response = await fetch('/api/track-custom-metric?type=summary');
  if (!response.ok) throw new Error('Failed to fetch metrics');
  return response.json();
}

Building React Components

Create visualization components in dashboard/src/components/analytics/ that consume your service functions:

// dashboard/src/components/analytics/CustomMetricChart.tsx
import { useEffect, useState } from 'react';
import { Bar } from 'react-chartjs-2';

export const CustomMetricChart = () => {
  const [data, setData] = useState<any>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/track-custom-metric?type=summary')
      .then(res => res.json())
      .then(setData)
      .finally(() => setLoading(false));
  }, []);

  if (loading) return <p>Loading metrics...</p>;
  if (!data) return <p>No data available</p>;

  return <Bar data={data} options={{ responsive: true }} />;
};

Embed the component in any Astro page:

// dashboard/src/pages/analytics.astro
---
import { CustomMetricChart } from '../components/analytics/CustomMetricChart';
---
<Layout title="Analytics">
  <h2>Custom Metric Overview</h2>
  <CustomMetricChart client:load />
</Layout>

Testing and Deployment

Run npm run dev from the dashboard directory to hot-reload your new endpoint locally. Astro automatically detects files in src/pages/api/ and maps them to the corresponding URL paths (e.g., track-custom-metric.ts becomes /api/track-custom-metric).

When ready for production, commit your changes and push to the repository. The Vercel CI/CD pipeline defined in .github/workflows/deploy.yml automatically redeploys the dashboard with your new endpoints.

Summary

  • Create endpoint files in dashboard/src/pages/api/ using kebab-case naming
  • Export named HTTP method handlers (POST, GET, OPTIONS) using the APIRoute type
  • Import CORS utilities from dashboard/src/lib/api/cors.ts to handle cross-origin requests
  • Reuse the Supabase client from dashboard/src/lib/api/neon.ts for database operations
  • Astro automatically registers routes based on file paths without explicit configuration
  • Deploy through the existing Vercel pipeline by pushing to the repository

Frequently Asked Questions

Do I need to manually register new API endpoints in Astro?

No. Astro's file-based routing automatically registers any file under dashboard/src/pages/api/ as an endpoint. The URL path mirrors the file path, so dashboard/src/pages/api/track-custom-metric.ts becomes available at /api/track-custom-metric without additional configuration.

What database client should I use for custom endpoints?

Use the Supabase client exported from dashboard/src/lib/api/neon.ts. This file instantiates a configured client singleton that reuses connection pools across requests, following the pattern established in track-download-supabase.ts and other analytics endpoints.

How do I handle CORS for cross-origin requests?

Import corsResponse and jsonResponse from dashboard/src/lib/api/cors.ts. Export an OPTIONS handler set to corsResponse (as shown in the reference implementations) and wrap all JSON responses with the jsonResponse utility to apply standard CORS headers automatically.

Where should I place frontend components that consume the new API?

Create React components in dashboard/src/components/analytics/ and import them into pages under dashboard/src/pages/. Use the client:load or client:visible directive in Astro files to hydrate interactive components that fetch data from your custom endpoints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →