Contribution skyline
Getting the data
Fetch GitHub contributions at build time, from a serverless function, or on a server, with or without a token.
Every component takes the same JSON:
interface ContributionData {
user: string;
total: number;
fetchedAt: string | null;
days: { date: string; level: 0 | 1 | 2 | 3 | 4; count: number }[];
}days runs oldest to newest, starting on a Sunday: 53 weeks × 7 days for a full year. level is GitHub’s own 0–4 shading.
At build time
The simplest option for a static site: fetch once per deploy and import the file.
npx contribution-skyline-fetch your-username --out src/data/contributions.json{
"scripts": {
"prebuild": "contribution-skyline-fetch your-username --out src/data/contributions.json"
}
}If the fetch fails, the CLI keeps the existing file and prints a warning. If there’s no file yet, it writes an empty one so your build still works.
From a serverless function
createContributionsHandler returns a standard Request → Response handler:
import { createContributionsHandler } from "@abhiramkrishna/contribution-skyline/fetch";
export const GET = createContributionsHandler({ cacheSeconds: 3600 });import { createContributionsHandler } from "@abhiramkrishna/contribution-skyline/fetch";
export default createContributionsHandler({ cacheSeconds: 3600 });import { createContributionsHandler } from "@abhiramkrishna/contribution-skyline/fetch";
const handler = createContributionsHandler({ cacheSeconds: 3600 });
export default { fetch: handler };- Request:
?user=picks the account. - Responses: the JSON with cache headers (
max-age,s-maxageandstale-while-revalidate). A bad username gets 400, an unknown user 404, and a GitHub failure 502. - One account only: pass
user: "you"so the endpoint can’t be used to look up other people.
The Web Components can load from it directly:
<contribution-skyline src="/api/contributions?user=you"></contribution-skyline>On a server
import { fetchContributions } from "@abhiramkrishna/contribution-skyline/fetch";
const data = await fetchContributions("your-username");It accepts an AbortSignal ({ signal }) and a custom fetch ({ fetch }), and throws an error with a readable message on failure.
Private contributions
Without a token you get the same calendar anyone sees on your GitHub profile. There are two ways to include private work:
- Profile setting, no token: turn on Include private contributions on my profile in your GitHub settings. Private work then appears as anonymous counts on your public calendar, and the token-free fetch reads it.
- Token from your own account: with a token, the helpers use GitHub’s GraphQL API, which returns the calendar as GitHub shows it to that account.
await fetchContributions("your-username", { token: process.env.GITHUB_TOKEN });
createContributionsHandler({ user: "your-username", token: process.env.GITHUB_TOKEN });For the CLI, set the token in CONTRIBUTIONS_TOKEN:
CONTRIBUTIONS_TOKEN=ghp_… npx contribution-skyline-fetch your-usernameWhat’s included depends on GitHub’s rules for your account, so compare the result with your profile once.