Blog

Internal Dashboards From Your Own API, Without Building a Frontend

6 min read

An internal dashboard is a private, read-only screen that shows your team how the business and the product are doing right now: signups, revenue, queue sizes, error rates, whatever someone checks first thing in the morning. The quickest way to build one is to skip the frontend: write a small endpoint for each number in the backend you already have, and let a dashboard tool render the JSON. This page covers what belongs on an internal dashboard, the three ways teams build them, and how to keep one private.

Internal dashboard vs admin panel

These get mixed up, and the difference decides which tool you need.

  • An admin panel lets people change things. Refund an order, ban a user, edit a record. It writes to your database, so it needs forms, validation, permissions and an audit trail.
  • An internal dashboard lets people see things. It's read-only by design. Nobody can break anything from it, which is exactly why it's safe to put on a TV in the hallway.

If you need the first, an internal-tool builder such as Retool, Appsmith or Budibase is the right category; our Retool alternatives page covers them. If you need the second, those tools are more than you need, and usually want direct database access to do it.

What goes on an internal dashboard

Different teams check different numbers, so most companies end up with a few small boards rather than one huge one:

TeamTypical widgets
Founders / leadershipMRR, signups this week, active users, runway
EngineeringDeploys per day, error rate, API health, open incidents
SupportOpen tickets, oldest ticket age, CSAT this week
SalesPipeline this month, deals won, quota progress
OpsOrders today, failed payments, queue backlog

Keep each board to six to eight widgets. If a number wouldn't make anyone act when it moves, it doesn't need a tile.

Three ways to build one

1. Build it yourself. A React app, a chart library, auth, hosting. It feels quick on day one; the cost arrives later, as maintenance nobody budgeted for. We wrote up the honest accounting in why building dashboards yourself costs more.

2. An internal-tool builder. Retool and similar tools connect to your database and let you drag charts onto a canvas. Powerful, and the right call for admin panels. For a read-only dashboard you're paying for a lot of surface area, and handing the tool database credentials.

3. API-first. Your backend already knows the numbers. (We compare all the kinds of dashboard builder separately.) Write an endpoint per widget that returns JSON in a fixed shape, and let a dashboard tool render it. No frontend, no database credentials in a third-party tool, and the logic stays in code you review.

The rest of this page is about the third approach, using dashboardbase.

What an endpoint returns

Each widget is one URL. An API-health tile with a live heartbeat looks like this:

response.json dashboardbase.com/s/your-company
{
  "title": "API health",
  "actions": [
    {
      "title": "Check Logs",
      "type": "link",
      "url": "https://example.com/status-logs"
    }
  ],
  "data": {
    "header": {
      "title": "Operational",
      "subtitle": "All checks passing"
    },
    "status": "Ok",
    "mode": "Heartbeat"
  }
}

In Heartbeat mode the status renders as a moving ECG-style pulse instead of a flat dot, which is readable from across a room.

When something breaks, the same endpoint flips to an error and raises an alert:

response.json dashboardbase.com/s/your-company
{
  "title": "Payments API",
  "actions": [
    {
      "title": "Open Incident",
      "type": "link",
      "url": "https://example.com/incident"
    }
  ],
  "data": {
    "header": {
      "title": "Down",
      "subtitle": "All checks failing"
    },
    "status": "Error"
  },
  "alert": {
    "active": true,
    "level": "critical",
    "message": "Payments API has been down for 8 minutes"
  }
}

That alert shows as a pulsing dot on the widget, and members who opted in get an email, a push notification on the native apps, or a Slack message.

A minimal endpoint

Here's a support-queue KPI in Node, reading from your own database:

const SECRET = process.env.DASHBOARDBASE_ENDPOINT_SECRET

// Fail at boot rather than serving internal data unprotected.
if (!SECRET) throw new Error('DASHBOARDBASE_ENDPOINT_SECRET is not set')

app.use('/dashboard', (req, res, next) => {
  if (req.get('x-dashboardbase-secret') !== SECRET) {
    return res.status(401).json({ error: 'unauthorized' })
  }
  next()
})

app.get('/dashboard/support/open-tickets', async (req, res) => {
  const { rows } = await db.query(`
    SELECT
      count(*) FILTER (WHERE status = 'open') AS open,
      count(*) FILTER (WHERE status = 'open' AND created_at < now() - interval '1 day') AS stale
    FROM tickets
  `)
  const { open, stale } = rows[0]

  res.json({
    title: 'Open tickets',
    actions: [{ title: 'Open Queue', type: 'link', url: 'https://example.com/support' }],
    data: {
      header: {
        title: String(open),
        subtitle: 'in the queue',
        badge: {
          text: `${stale} older than 1 day`,
          color: stale > 0 ? 'Warning' : 'Success',
        },
      },
    },
  })
})

That's the whole pattern. The query is yours, the definition of "stale" is yours, and it lives in your repo with the rest of your code. API dashboard examples has the JSON for every other widget type. Check any response in the public endpoint validator before wiring it up.

Writing ten of these by hand is an afternoon. With the free Skill, Claude Code or Cursor writes them in the right shape on the first try, or the editor generates a prompt for whichever AI tool you already use.

Keeping it internal

"Internal" is a security requirement, not a label. With an API-first setup, privacy comes from three layers:

  • Your endpoints refuse strangers. dashboardbase sends the workspace secret in the x-dashboardbase-secret header on every request. When you test a datasource, it also makes one request with every credential stripped and reports what came back: a green "Protected" if your endpoint returned 401, a yellow warning if it handed over data.
  • Dashboards are workspace-only by default. Members sign in to see them; only owners can make a dashboard public, and public links can carry a password.
  • TVs don't log in. A paired screen holds a narrow display token that can read only the dashboards assigned to it, and you can revoke it from the Devices list. How TV pairing works.

Nothing is stored on our side; dashboardbase reads from your endpoints and renders.

Where people look at it

  • The hallway TV, paired by code at www.dashboardbase.com/tv, rotating through several dashboards.
  • Their phones, through the native iOS and Android apps, with push notifications on alerts.
  • A browser tab that refreshes every 1, 5, 10 or 30 minutes.

When this isn't the right approach

  • People need to act from the dashboard. Use an internal-tool builder for admin panels.
  • Analysts need to explore. A BI tool such as Metabase is built for ad-hoc questions.
  • Nobody can write an endpoint. A connector-based dashboard tool will get you further.

Pricing

Flat plans with a seat ceiling, from $9.99/month (Startup, 3 seats) to $29.99 (Team, 10 seats) and $79.99 (Business, 25 seats). You don't pay per dashboard, and there's a 14-day free trial.

FAQ

What is an internal dashboard? A private, read-only view of business or product metrics for your own team, not your customers.

What's the difference between an internal dashboard and an admin panel? A dashboard shows data; an admin panel changes it.

How do I build an internal dashboard without a frontend? Write an endpoint per widget that returns JSON in a dashboard tool's contract, and let the tool render it.

Do I have to give a dashboard tool database access? Not with an API-first tool. It reads only what your endpoints return.

Your first dashboard in ten minutes.

Return JSON from an endpoint you already own. We handle the charts, hosting, sharing and the mobile app — free for 14 days.