Skip to content

Most Used APIs

Mark Bouslog edited this page Mar 20, 2026 · 6 revisions
  • This is an outline to be updated *

APIs used in Zooniverse's frontend

Panoptes

Server-side vs Client-side

https://github.com/zooniverse/front-end-monorepo/pull/3345

ERAS

ERAS (Enhanced Running Average Stats Service) is Zooniverse's stats service for measuring volunteer effort and contribution. You can find comprehensive technical documentation in the ERAS Wiki.

What ERAS Does

ERAS provides statistics for comments and classifications. Classifications are grouped by user or (user) group. Comments and classifications can be bucketed by day, week, month, or year, and can be scoped to a project or workflow. Requests can be made for a specific date range or for all time.

How FEM Uses ERAS

Some of the components that use ERAS stats include, but are not limited to:

Basic ERAS GET Examples

For project-scoped user classifications, bucketed by day:

GET https://eras.zooniverse.org/classifications/users/12345?project_id=6789&period=day

For a bounded 7-day window:

GET https://eras.zooniverse.org/classifications/users/12345?project_id=6789&period=day&start_date=2023-05-01&end_date=2023-05-08

ERAS Hook Example

The same request shape through a stats hook:

const { data: stats, error, isLoading } = useStats({
  endpoint: '/classifications/users',
  sourceId: '12345',
  query: {
    project_id: '6789',
    period: 'day',
    start_date: '2023-05-01',
    end_date: '2023-05-08'
  }
})

The hook determines the proper ERAS host (production or staging), provides client-side authorization, loading/error state, and response caching.

ERAS Response

See the ERAS Wiki for detailed request and response documentation, including field definitions and example responses.

UTC

In accordance with ADR 61, FEM shows ERAS stats in UTC.

Caesar

Caesar is Zooniverse's aggregation service. FEM fetches reductions via GraphQL and renders them as consensus lines (transcription) or pre-populated marks (drawing).

For background on why this works the way it does, see ADR 60. For hook API docs, see the Hooks README. For test projects, see Benchmark Projects.

Data Flow

Workflow.caesarReducer → 'alice' | 'machineLearnt' | ''
       ↓
useCaesarReductions(key) → GraphQL fetch → Subject.setCaesarReductions()
       ↓                                          ↓
useTranscriptionReductions()          useMachineLearntReductions()
       ↓                                          ↓
TranscribedLines.jsx                  DrawingToolMarksConnector.jsx
Step File What to check
Reducer key Workflow.js L53-61 Transcription: task type === 'transcription''alice'. Drawing: enable_caesar_data_fetching === true + compatible tool type'machineLearnt'. Empty string → no fetch.
Config flag WorkflowConfiguration.js enable_caesar_data_fetching (default false). Set via PFE project builder behind caesarDataFetching experimental flag.
GraphQL fetch useCaesarReductions.js Fires on subject change. Errors go to Sentry + console.
Client ClassifierContainer.jsx L25-34 Prod: caesar.zooniverse.org/graphql. Other: caesar-staging.zooniverse.org/graphql.
Storage Subject.js L10, L25 CaesarReductions union type discriminated by reducer literal. caesarReductionsLoadedForStep prevents duplicate mark creation.
Transcription TranscriptionReductions.jsuseTranscriptionReductions.jsTranscribedLines.jsx consensusLines(frame) → SVG overlays. Visibility gated by shownMarks === ALL and lines.length > 0.
Drawing MachineLearntReductions.jsuseMachineLearntReductions.jsDrawingToolMarksConnector.jsx findCurrentTaskMarks({ stepKey })tool.createMark(). Mark shape must match reducedSubjectMocks.js.

Debugging

No data loading? Walk the chain:

  1. classifierStore.workflows.active.caesarReducer — empty string means Caesar won't fetch. Check task type and config flag.
  2. Network tab → caesar.zooniverse.org/graphql — no request means subject?.id or reducerKey is falsy.
  3. Response empty → Caesar-side issue (extractors/reducers not configured). Test directly: curl -X POST https://caesar.zooniverse.org/graphql -H 'Content-Type: application/json' -d '{"query":"{ workflow(id: ID) { subject_reductions(subjectId: ID, reducerKey: \"KEY\") { data } } }"}'
  4. classifierStore.subjects.active.caesarReductions null → race condition (subject changed before fetch resolved).

Data loading but marks wrong? Compare against reducedSubjectMocks.js for expected field shapes.

Adding a New Drawing Tool Type

  1. Add tool type string to the toolTypes array in Workflow.js L103
  2. Add mock to reducedSubjectMocks.js
  3. Verify the tool's MST model accepts the fields Caesar outputs (may need field name mapping in the hook)
  4. Add test case to MachineLearntReductions.spec.js

Adding a New Task Type

Currently only two paths exist (transcription + drawing). Mixed reducer types in one workflow are not supported. To add a third:

  1. New MST model with reducer: types.literal('key') → add to union in Subject.js L10
  2. New condition in Workflow.js :: caesarReducer
  3. New wrapper hook consuming useCaesarReductions(key) → wire into component

Sugar

Talk

Talk is Zooniverse's message-board space. Each project has its own Talk boards that act as a forum for volunteers to interact with one another as well as the research team. You can find the API source code at the Talk API repository.

Resource Hierarchy

Talk organizes content in the following hierarchy:

Level Description Examples
Board A top-level container for discussions around a specific topic Notes (on subjects), Help, or Chat
Discussion A parent of comments, grouping related conversation threads within a board Subject 987, Issue with Workflow, or Favorite Planet
Comment An individual message or response within a discussion "Is it an alien?", "I can't draw on the image", or "Jupiter is the best!"

Basic Talk GET Examples

For retrieving all discussions in a board:

GET https://talk.zooniverse.org/boards/1/discussions

For retrieving discussions scoped to a specific project and subject, sorted by most recent comment activity:

GET https://talk.zooniverse.org/discussions?section=project-6789&focus_id=12345&focus_type=Subject&sort=-last_comment_created_at

For retrieving all comments in a discussion, sorted by newest first:

GET https://talk.zooniverse.org/discussions/123/comments?sort=-created_at

talkAPI from @zooniverse/panoptes-js

Typically, FEM uses the talkAPI client, often with a custom hook.

talkAPI Custom Hook Examples

The request for discussions scoped to a specific project and subject, through a talk API discussions hook:

const { data: discussions, error, isLoading } = useDiscussions({
  section: 'project-6789',
  focus_id: '12345',
  focus_type: 'Subject',
  sort: '-last_comment_created_at'
})

The request for all comments in a discussion, sorted by newest first, through a talk API comments hook:

const { data: comments, error, isLoading } = useComments({
  discussion_id: '123',
  sort: '-created_at'
})

The hooks handle client-side authorization with Panoptes auth tokens and provides loading/error state management via SWR.

Authorization

Certain Talk resources require specific user roles or permissions:

  • Moderation endpoints require moderator or admin roles
  • Comment, Discussion, and Board creation/editing requires authentication
  • Resources may have role-based access controls

Moderation

Moderation is supported through the Talk API. [additional moderation documentation coming soon]

Tags

The Talk API supports tags. [additional tags documentation coming soon]

Examples

Some examples of FEM components that use Talk data include, but are not limited to:

Contentful

Zooniverse Blogs