How To Track Developer Activity Across GitHub, GitLab, and Bitbucket using a Unified Repository API
April 10, 2026
To track developer activity across GitHub, GitLab, and Bitbucket, you need consistent access to repository and commit data across multiple APIs.
With Unified's Repository API, you can:
- retrieve repositories
- fetch commit history
- track updates over time
using a single, normalized interface.
This guide walks through how to implement a complete commit tracking pipeline.
What makes commit tracking complex
Commits are repository-scoped
There is no global endpoint for commits.
You must:
- list repositories
- retrieve commits per repository
This applies across GitHub, GitLab, and Bitbucket.
Update models are inconsistent
Commit updates are not handled the same way:
- GitHub → commit-related events supported
- GitLab → commit-related events supported
- Bitbucket → no commit events
This requires:
- webhook ingestion where available
- polling using
updated_gtewhere not
Pagination is required
All commit retrieval is paginated:
- max
limit= 100 offsetis required for iteration
You must loop until all results are retrieved.
Step-by-step implementation
Step 1: List repositories
Start by retrieving repositories for a connection:
const repos = await sdk.repo.listRepoRepositories({
connectionId,
limit: 100,
offset: 0,
sort: 'updated_at',
order: 'asc',
fields: ['id', 'name', 'updated_at', 'org_id'],
});
This defines the scope of commit tracking.
Step 2: Retrieve commits per repository
Commits must be fetched per repository:
const commits = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
limit: 100,
offset: 0,
sort: 'updated_at',
order: 'asc',
fields: [
'id',
'user_id',
'repo_id',
'message',
'created_at',
'updated_at',
'branch_id',
],
});
Step 3: Paginate through commit history
Retrieve all commits using pagination:
let offset = 0;
const limit = 100;
while (true) {
const page = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
limit,
offset,
sort: 'updated_at',
order: 'asc',
});
await processCommits(repo.id, page);
if (page.length < limit) break;
offset += limit;
}
Step 4: Track incremental updates
Use updated_gte to retrieve only new or modified commits:
const commits = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
updated_gte: lastSyncAt,
limit: 100,
offset: 0,
sort: 'updated_at',
order: 'asc',
});
This avoids reprocessing full history.
Step 5: Use commit events where available
Unified exposes commit-related webhook events for:
- GitHub
- GitLab
Bitbucket does not provide commit events.
Recommended pattern:
- subscribe to commit events for GitHub and GitLab
- ingest updates as they occur
- use polling for Bitbucket
Both flows should feed the same processing pipeline.
Step 6: Poll where events are unavailable
For integrations without commit events:
const commits = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
updated_gte: lastSyncAt,
limit: 100,
});
Run this on a schedule to maintain up-to-date data.
Step 7: Reduce payload size
Only request required fields:
fields: ['id', 'user_id', 'repo_id', 'created_at', 'updated_at']
This reduces latency and unnecessary upstream calls.
Step 8: Access provider-specific fields
If needed, include raw data:
const commit = await sdk.repo.getRepoCommit({
connectionId,
id: commitId,
fields: ['id', 'message', 'raw'],
});
The raw field contains original provider payloads.
Step 9: Optional branch-level filtering
If you need branch-specific insights:
const commits = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
branch_id: branch.id,
limit: 100,
});
End-to-end example
const repos = await sdk.repo.listRepoRepositories({
connectionId,
limit: 100,
offset: 0,
});
for (const repo of repos) {
let offset = 0;
const limit = 100;
while (true) {
const commits = await sdk.repo.listRepoCommits({
connectionId,
repo_id: repo.id,
updated_gte: lastSyncAt,
limit,
offset,
sort: 'updated_at',
order: 'asc',
fields: [
'id',
'user_id',
'repo_id',
'message',
'created_at',
'updated_at',
'branch_id',
],
});
if (!commits.length) break;
await processCommits(repo.id, commits);
if (commits.length < limit) break;
offset += limit;
}
}
What this enables
- developer activity tracking
- commit-based analytics
- engineering reporting
- AI workflows using commit history
- automation triggered by repository activity
Summary
To track commits across repository integrations:
- list repositories first
- retrieve commits per repository
- paginate through results
- use
updated_gtefor incremental updates - combine webhook ingestion and polling
- normalize data into a single pipeline
Unified lets you implement this once and support multiple repository platforms without maintaining separate integrations.