Before you start
You need:- A Labelbox API key.
- Access to performance data. If you can open a project’s Performance dashboard, you can read that project through the API. Workspace reports need permission to view performance across your organization, as the Monitor does.
- For the Python examples, Python SDK version 7.13.0 or later.
GET requests under this base URL, authenticated with your API key as a bearer token:
Quick start
Get the number of labels created per day in a project:Endpoints
Every table is paged. Filters lists which parameters each report takes. See Paging and Reliability before you build on the API.
Units and dates
- Time is in seconds.
- Percentages and agreement scores are fractions from 0 to 1. A value of
0.9means 90%. - Dates are calendar days in UTC, written as
2026-01-31. Reports are bucketed by UTC day.startDateandendDateare the first and last day of the period, both included, and a request can cover at most 366 days. - Wider buckets keep their calendar bounds: a week runs from Monday, a month from the 1st. The first and last bucket of a series can reach beyond your period, but they count only the days inside it. For counts and time totals, a wider bucket is the sum of its days. Averages and percentages are worked out over the whole bucket, so they are not.
date, a datetime, or a string. A datetime with a time zone is converted to its UTC day.
Metrics
List the metrics available to you, with their units and definitions:Throughput
Efficiency
Average handling time includes creating, reviewing, and reworking time. The
aht_ metrics are listed and can be queried only when average handling time charts are enabled for your organization. Their buckets also carry modes, the handling time split into creating, reviewing, and reworking.
Quality
The two distribution metrics return score ranges instead of time intervals. Their response has
"bucketType": "score" and ten buckets, each with rangeStart, rangeEnd, and value, the number of labels whose score falls in that range. The ranges are fractions like the scores themselves: 0 to 0.1, up to 0.9 to 1.
Filters
These parameters narrow a report. Lists are comma-separated in a request, or a Python list in the SDK.
A user group filter follows the group’s current membership. A group that is empty, is no longer attached to the project, or that you cannot view matches no work.
A parameter that an endpoint does not have is refused by name, so a misspelled filter never runs an unfiltered report.
A list that is sent must name at least one ID. An empty list is refused with
400 (userIds=), and the Python SDK raises ValueError for one (user_ids=[]). It is not read as “no filter”, which would report on everyone. To leave a filter off, leave the parameter out, or pass None in the SDK.
Labeler and reviewer totals
These are the two tables on the Performance dashboard: one row per member with their totals for the period.data and adds page, perPage, and total:
Labeler fields
The Python SDK uses the same names in snake case, such aslabels_created.
Reviewer fields
Download the report
Get a link to the project’s performance report as a file. This is the file the Download button on the Performance dashboard gives you.url and expiresInSeconds. The link works for 24 hours.
Workspace reports
Workspace reports are the Monitor’s data. They cover every project your organization owns and every project another organization shares with yours, or only the projects you name inprojectIds.
workspace/labelers returns one row for each labeler on each project they worked on in the period. A row has the labeler fields, without avgRating, plus:
The table is paged like the project tables. Without
sort, rows are ordered by project, then member.
Workspace reports do not take a user group filter.
Shared projects and workforce providers
A project belongs to one organization and can be shared with another, for example when you add a workforce provider to it. The provider’s members then work in your project, and the project appears in the provider’s workspace as a shared project. The API reflects both sides of that connection. What a workspace report covers. The projects your organization owns, and the projects shared with it. Two fields tell them apart on every row ofworkspace/labelers:
projectOrganizationIdis the organization that owns the project.memberTypeis whose member did the work:internalfor a member of your organization,externalfor a member of another organization or an Alignerr member. The Monitor calls external members Workforce members.
internal, and a customer’s project has the customer’s projectOrganizationId. Alignerr members are the exception: they are external to everyone, including to Alignerr’s own organization.
Split a report. Use memberType and ownerOrganizationIds on either workspace report. These are the Monitor’s Member Type and Owned by filters.
- A split covers members and projects with activity in the period. As on the Monitor,
memberTypeandownerOrganizationIdsselect from the members and projects that have rows in the report for your dates and other filters. If none match, every bucket is zero. It is never the unfiltered report. - A split by owner leaves out projects that are gone. A project that can no longer be found has no owner, so
ownerOrganizationIdsnever selects it, and the splits by owner can add up to slightly less than the whole workspace. - A split by owner leaves out projects you cannot report on. Your workspace can include a project you have no role in. A metric split by
ownerOrganizationIdsdoes not count it, and lists it inskippedProjectIdsso that you know. - A split of a metric needs permission to view everyone’s performance. With
projectIds,memberTypeandownerOrganizationIdsonworkspace/metricsneed permission to view all performance in every project you name. Otherwise the request returns403. Onworkspace/labelersthey filter the rows you can already see. - Project reports carry
memberTypetoo. The labeler and reviewer tables of a project give each member’smemberType. - Names and emails are masked between a customer and a workforce provider. See Access and privacy. IDs are never masked, so you can always group and filter by
userId,projectId, andprojectOrganizationId. - User groups belong to the project’s organization. A
userGroupIdsfilter on a project shared with you matches no work.
Paging
The three tables (projects/{projectId}/labelers, projects/{projectId}/reviewers, and workspace/labelers) are paged. In the Python SDK, iterating fetches one page at a time, and total gives the number of rows without reading them all:
Python
Every response has
page, perPage, and total, the number of rows across all pages. Request pages until you have total rows. A page past the end returns an empty data.
cURL
- Leave the cache on. The pages of
workspace/labelersare cut from one reading of the report, kept for five minutes, so they agree with each other and the rows are in a fixed order.cachedAtsays when that reading was taken. WithuseCache=falseevery page reads the report again. - Sorting. Every table sorts by the figures in its rows, such as
labelsCreatedoravgTimePerLabel, exceptavgRating. Withoutsort, the project tables come ordered by email, as on the Performance dashboard, and rows that tie under a sort are in that order too. A masked email keeps the place of the real one.workspace/labelerscomes ordered by project, then member. - Metrics are not paged. A metric returns at most one bucket per day of the period, and the period is limited to 366 days.
Access and privacy
The API shows you what the pages show you.- Your own performance only. If you can only view your own performance on a project, every project report returns only your data, whatever
userIdsyou pass. - Workspace reports. Without
projectIds, you need permission to view performance across your organization. WithprojectIds, you need performance access to each project you name. - Projects you cannot see. A project you have no performance access to returns
404, the same as a project that does not exist. - Splitting by member type or owner. On
workspace/metrics,memberTypeandownerOrganizationIdsneed permission to view all performance in every project you name inprojectIds. A project found through its owner that you cannot report on is left out and listed inskippedProjectIds. - Masked emails. The email of a member you may not identify is replaced with a masked value, as on the pages. For example, a workforce provider’s members appear masked to the project’s owner, and the owner’s members appear masked to the provider.
- Masked project and organization names. A workforce provider does not see the names of the projects shared with it or of the organizations that own them. In
workspace/labelers,projectNameandprojectOrganizationNameare replaced with masked values for those projects. The IDs are unchanged. - Restricted API keys. A key created with a limited set of permissions needs a performance permission, and is limited to the ones it has. A key that only has permission to view your own performance returns only your own.
Data freshness
The API reads the same data as the Performance dashboard and the Monitor, so it is never more current than those pages. That data is rebuilt periodically, not continuously: the current day’s figures can trail real activity by anything from a quarter of an hour to over an hour. A response served from the cache can be up to five minutes older again.generatedAt is when the response was produced. cachedAt, on the labeler tables, is set when the rows came from a result computed in the last few minutes. Neither tells you how recent the underlying activity data is, and no response carries an as-of time for it.
Two things follow for the current day:
- Today’s bucket keeps growing. Read settled days for totals you will not revisit.
- Charts and tables do not refresh together. For settled days a metric and the labeler table normally add up to the same total. For the current day they can differ until both have caught up.
Limits
Requests count toward your API rate limit, like the rest of the Labelbox API.
Reliability
- Requests are safe to repeat. Every endpoint is a
GETand changes nothing, so you can retry any request. - Retry
5xxresponses and timeouts with a growing delay between attempts. The Python SDK does this for you, for up to four minutes, and tries once more after a request that timed out. When it stops retrying, it raises the error that kept happening. - Do not retry
4xxresponses without changing the request. For429, wait before sending more. - Allow for long requests. Reports are computed when you ask, and a long period over a large workspace can take a while. The Python SDK waits up to 120 seconds for a response.
- Prefer fewer, wider requests. One request for a month at
interval=daycosts less than a request for each day. To read every member’s totals for a project as a file, use Download the report. - Expect new fields. Responses can gain fields over time. Ignore the ones you do not know. The Python SDK does.
Errors
The Python SDK raises
TimeoutError when a request gets no response in time, and NetworkError when it cannot connect. All of these exceptions are in lbox.exceptions. It raises Python’s ValueError, before sending anything, for a filter given as an empty list.
A 400 response names each parameter that was refused: