chartshot
Docs menu

JavaScript SDK

Draw charts, sign chart URLs and store charts from JavaScript or TypeScript, and put charts in React emails.

The JavaScript and TypeScript SDK draws charts, signs chart URLs and stores charts with your key. It has no dependencies and runs on your server: Node 20 and up, and edge runtimes such as Vercel's and Cloudflare Workers. It's published as ES modules only (import, or require() on Node 20.19 and up) and its types need TypeScript 5 and up.

Shell
npm install @lglab/chartshot

Set up the client

Create a key on the Keys page and keep its secret key and public id in your server's environment, as CHARTSHOT_SECRET_KEY and CHARTSHOT_PUBLIC_ID. Then make one client, in a file such as charts.ts:

TypeScript
import { Charts, type ChartSpec } from "@lglab/chartshot";

export const charts = new Charts({
  secretKey: process.env.CHARTSHOT_SECRET_KEY!,
  publicId: process.env.CHARTSHOT_PUBLIC_ID,
});

The public id is needed only to sign URLs. The secret key must stay on your server, so use the SDK in server code only, never in a browser bundle.

ChartSpec types every field of the spec, with each field's description, so your editor completes and checks specs as you write them:

TypeScript
const spec: ChartSpec = {
  type: "line",
  data: {
    labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
    series: [{ name: "Signups", values: [12, 18, 15, 22, 30] }],
  },
  options: { title: "Weekly signups" },
};

Draw a chart

render sends the spec to POST /v1/render and returns the image's bytes, for code that attaches, uploads or saves it:

TypeScript
import { writeFile } from "node:fs/promises";

const { image, alt } = await charts.render(spec);
await writeFile("signups.png", image);

alt describes the chart in words. Use it as the image's alt text.

Sign a URL

signUrl returns a chart URL signed with your key, for an <img> in an email, a Slack message or a page. It needs no request, so it's instant:

TypeScript
const url = charts.signUrl(spec); // works for 90 days
const short = charts.signUrl(spec, { expiresIn: "7d" });
const forever = charts.signUrl(spec, { expiresIn: null });

expiresIn takes seconds, or a number with s, m, h or d. The 90-day default means a URL that leaks stops drawing on your plan. Signed URLs come with Pro and up; see keys and signed URLs for how they work.

A URL over 8 KB throws, since some email clients refuse long URLs. Store the chart instead.

Store a chart

create draws the chart, stores the image and returns a short URL. It's the best choice for emails: the URL is short, the image is drawn once, and it keeps working after you change your key.

TypeScript
const chart = await charts.create(spec);
// { id, url: "https://c.chartshot.dev/….png", format, width, height, alt, expiresAt }

await charts.deleteChart(chart.id);

Stored charts come with Pro and up, and are kept for 90 days on Pro and a year on Team and Business.

Charts in React and react-email

ChartImage renders an <img> with a signed URL, the chart's width and height, and alt text:

TypeScript
import { ChartImage } from "@lglab/chartshot/react";
import { Body, Html, Text } from "@react-email/components";
import { charts } from "./charts";

export default function WeeklyReport({ signups }: { signups: number[] }) {
  return (
    <Html>
      <Body>
        <Text>Here are this week's signups.</Text>
        <ChartImage
          charts={charts}
          spec={{
            type: "bar",
            preset: "email",
            data: {
              labels: ["Mon", "Tue", "Wed", "Thu", "Fri"],
              series: [{ name: "Signups", values: signups }],
            },
            options: { title: "Weekly signups" },
          }}
        />
      </Body>
    </Html>
  );
}

It signs as it renders, with no request, so it works anywhere React renders on a server. The alt text is the alt prop if you pass one, else the spec's alt, else the chart's type and title, such as "Bar chart: Weekly signups". render and create return a fuller description. Other props, such as style, go to the <img>.

Usage

TypeScript
const usage = await charts.usage();
// { plan: "pro", renders: { used: 1240, included: 10000, limit: 11000, remaining: 8760 }, … }

It returns the same as GET /v1/usage.

Errors and warnings

When the API refuses a request, the SDK throws a ChartshotError with the API's code and message, the HTTP status, issues listing each field at fault, the requestId to quote to support, and retryAfter in seconds for rate_limited:

TypeScript
import { ChartshotError } from "@lglab/chartshot";

try {
  await charts.render(spec);
} catch (error) {
  if (error instanceof ChartshotError && error.code === "invalid_spec") {
    console.error(error.issues); // [{ path: "data.series[0].values", message: "…" }]
  }
  throw error;
}

The error codes are in the API reference.

Fields the spec sets that Chartshot doesn't know don't stop the chart. They are ignored, returned as warnings from render and create, and logged with console.warn. Pass onWarnings to the client to handle them yourself:

TypeScript
const charts = new Charts({
  secretKey: process.env.CHARTSHOT_SECRET_KEY!,
  onWarnings: (warnings) => logger.warn({ warnings }, "chart spec has unknown fields"),
});

Options

OptionWhat it does
secretKeyYour secret key, sk_live_…. Required.
publicIdYour key's public id, pk_live_…. Needed by signUrl and ChartImage.
baseUrlThe API's address. Defaults to https://api.chartshot.dev.
fetchThe fetch to call the API with. Defaults to the global one.
onWarningsCalled with the fields a spec set that were ignored. Defaults to console.warn.