Skip to content

Getting Started

React:

Terminal
npm install @meterry/component @meterry/component-react echarts echarts-for-react

Vue 3:

Terminal
npm install @meterry/component @meterry/component-vue echarts vue-echarts

Use matching core and framework package versions. To add optional default styles:

Terminal
npm install @meterry/component-tailwindcss
Need Component Application-owned work
Query, paginate and render usage MeterUsageTable Auth endpoint and query; no load, data, mapper or cursor loop
Query, aggregate and render charts MeterUsageChart Auth endpoint, metrics and grouping; no pivot or series definitions
Existing summary widget MeterUsage Existing summary API; its behavior is unchanged
Render your own complete rows / custom loader MeterTable columns plus data, load or controller
Render your own chart data MeterChart data, x, series and request lifecycle

The advanced components remain supported. MeterTable.load calls your loader when its table query changes; it does not automatically follow a Meter cursor. MeterTable.data paginates only the rows provided. Neither can discover a second server batch without application logic. Choose the automatic wrappers instead for standard usage queries.

Your authenticated backend exposes GET /api/meter/subject-token, determines the subject from the session, calls Grant Subject Token using its server-only project API key, and returns the grant JSON (access_token, expires_at or expires_in). Never put a tenant API key in browser code. A token needs the analysis rule and access to the selected metrics.

The provider’s tokenEndpoint helper uses GET and session credentials (include by default). A shared SubjectClient handles token single-flight, expiry refresh and one 401 retry. Passing client takes precedence over getJwt, then tokenEndpoint. Provider options.fetch applies to both token and API requests.

import { MeterClientProvider, MeterUsageTable, MeterUsageChart } from '@meterry/component-react'
import type { TableColumn, UsageTableRow } from '@meterry/component'
// Current Meter API event identity. No row mapping or pagination logic.
const eventColumns: TableColumn<UsageTableRow>[] = [
{ key: 'raw_event_id', header: 'Event ID' },
{ key: 'source', header: 'Source' },
{ key: 'occurred_at', header: 'Occurred at', format: (value) => new Date(Number(value) * 1000).toLocaleString() },
]
export function UsageDashboard() {
return (
<MeterClientProvider
tokenEndpoint="/api/meter/subject-token"
options={{ baseUrl: '', credentials: 'include', tokenStorage: null }}
>
<MeterUsageTable source="events" columns={eventColumns} rangeDays={7} pageSize={20} />
<MeterUsageChart type="line" rangeDays={7}
query={{ metrics: ['input_tokens', 'output_tokens'], group_by: ['bucket', 'model'] }} />
<MeterUsageChart type="doughnut" rangeDays={7}
query={{ metrics: ['input_tokens'], group_by: ['model'] }} />
</MeterClientProvider>
)
}

baseUrl: '' assumes your Subject API is served at same-origin /v1/.... Configure a real API origin or proxy prefix otherwise. The token endpoint is your application route, not the Meter grant route. Use metric names that exist in your project. tokenStorage: null keeps tokens in memory; if persisting them, use an authentication-scoped tokenStorageKey.

Provide the client in an ancestor. Vue injection does not read a provide from the same component’s setup.

App.vue:

<script setup lang="ts">
import { provideMeterClient } from '@meterry/component-vue'
import UsageDashboard from './UsageDashboard.vue'
provideMeterClient({
tokenEndpoint: '/api/meter/subject-token',
options: { baseUrl: '', credentials: 'include', tokenStorage: null },
})
</script>
<template><UsageDashboard /></template>

UsageDashboard.vue:

<script setup lang="ts">
import { MeterUsageTable, MeterUsageChart } from '@meterry/component-vue'
import type { TableColumn, UsageTableRow } from '@meterry/component'
const eventColumns: TableColumn<UsageTableRow>[] = [
{ key: 'raw_event_id', header: 'Event ID' },
{ key: 'source', header: 'Source' },
]
</script>
<template>
<MeterUsageTable source="events" :columns="eventColumns" :range-days="7" :page-size="20" />
<MeterUsageChart type="area" :range-days="7"
:query="{ metrics: ['input_tokens', 'output_tokens'], group_by: ['bucket', 'model'] }" />
<MeterUsageChart type="pie" :range-days="7"
:query="{ metrics: ['input_tokens'], group_by: ['model'] }" />
</template>

Alternatively pass :client="client" explicitly to each component. Vue automatic component refs expose refresh().

  • Events use after_id / next_after_id lazily. Default API batches contain up to 500 rows; with 20-row pages, page 26 automatically requests the next batch when a cursor exists. Cached pages do not refetch.
  • source="usage" fetches one bounded aggregate result and pages locally. The aggregate API has no cursor; a limit warning is not an all-data result.
  • Trend charts query Analysis, preserve metrics and dimensions as separate series, and sum duplicate bucket/series points. Pie/doughnut query Usage and require one metric and one additive measure.
  • Potentially truncated charts are hidden by default. allowPartial explicitly displays the prefix with a warning. Do not assume a partial pie shows the whole account.
  • Same-client/same-query chart requests share pending work and 30-second cached results. Clear the client token/query cache and remount/refetch on auth-scope changes; never reuse a previous user’s data.

Register the plugin in your Tailwind config:

import meterPlugin from '@meterry/component-tailwindcss'
export default {
content: ['./src/**/*.{js,ts,jsx,tsx,vue}'],
plugins: [meterPlugin],
}

With Tailwind v4 you can also do it in CSS (components emit semantic classes by default, e.g. meter-card, meter-table, meter-chart):

@import "tailwindcss";
@plugin "@meterry/component-tailwindcss";
/* The meter-* class names live as strings in the core package source, so
Tailwind needs to scan them. When consuming the published package, point
@source at the dist entry: */
@source "../node_modules/@meterry/component/dist/index.js";

See Theming & Styles for details.

For a table with headers and append-only rows instead of page navigation, use MeterUsageList / MeterList.