Offset vs Cursor Pagination: Stable API Traversal Guide

Offset vs Cursor Pagination

Scrapeless Agent Browser provides cloud browser automation for workflows that navigate paginated web pages.

TL;DR

  • Offset pagination identifies a position. It is convenient for numbered pages and direct jumps within a bounded result set.
  • Cursor pagination identifies a continuation point. Clients should preserve the returned token and the query that produced it.
  • A stable sort needs a unique tie-breaker. Equal timestamps alone cannot reliably define the boundary between pages.
  • Neither pagination style guarantees a frozen dataset. Snapshot behavior must be an explicit service contract.
DimensionOffset paginationCursor pagination
Request modelSkip a requested number of resultsContinue from a returned token
NavigationDirect page jumps are naturalSequential traversal is natural
Changing dataPositions can shift between requestsBoundary stability depends on sort and implementation
Database workLarge offsets can require substantial skipped workIndexed keyset designs can seek from a boundary
Client stateQuery plus page or offsetQuery plus opaque token and completion state
Snapshot semanticsRequires a separate consistency mechanismRequires a separate consistency mechanism

What Offset and Cursor Actually Identify

Offset pagination asks a collection to skip a position-based prefix and return the next slice. Cursor pagination asks the service to continue relative to a previously returned boundary. In offset vs cursor pagination, the important difference is what the client remembers between requests. One remembers how far it has counted; the other remembers where the service told it to continue.

A cursor is an API abstraction, while keyset pagination is a query technique. A token may encode sort values, refer to server-side state, or even wrap an offset. Inspect the documented behavior before assuming an opaque string implies an efficient database seek. The opaque page-token contract provides a useful model: clients return tokens without interpreting their contents.

Why Ordering Comes Before Page Size

A predictable traversal requires an ordering that distinguishes every record. Sorting only by a non-unique value leaves boundary ties unresolved. For example, a collection of articles can contain several items with the same creation timestamp. A unique identifier can break that tie, provided its ordering and comparison rules remain consistent across requests.

The SQL ordering rules make the absence of an explicit order significant: the database does not promise a useful default sequence. Record the complete sort specification with the collection run. Changing ascending to descending order, changing a filter, or changing a locale-sensitive comparison can invalidate the meaning of a saved continuation point.

How Offset Pagination Behaves During Writes

Offset boundaries can move when earlier records are inserted or deleted. Consider a hypothetical list in which the first page ends at item D. A new item inserted before A changes the positions of subsequent records. Asking to skip the old page length can bring D back into the next slice. Deleting an earlier item can shift an unseen record into the skipped prefix.

These examples describe position changes, rather than a defect in a particular API. Offset pagination remains useful for a small, relatively stable administrative list where users value numbered navigation. The LIMIT and OFFSET semantics also explain why deep offsets can be expensive: skipped rows still require server work. Measure your actual filtered query before setting a navigation limit.

Where Keyset Cursors Help and Where They Stop

Keyset pagination can continue after the last observed sort tuple instead of recounting earlier positions. With a suitable index and query plan, that avoids the same kind of skip work as a deep offset. It also avoids some position shifts caused by inserts before the boundary. The benefit belongs to the implementation, rather than to the token format.

Mutable sort keys remain a problem. If an item changes its ranking score after you pass its original position, it can move into or out of the unvisited region. A deletion can make a boundary record disappear. A correct service must define how its token behaves in those cases. For an export requiring an exact historical membership set, request a snapshot or another explicit consistency boundary.

Read the Continuation Contract as a Consumer

The response contract determines when a consumer stops. A service may return a dedicated next token, a next link, or structured page information. Do not infer completion solely from a short page unless the API explicitly defines that behavior. Preserve tokens byte for byte, including their encoding, and do not manufacture the next token from visible record IDs.

The GraphQL connection model separates record edges, cursors, and page information. Its forward and backward arguments illustrate that cursor navigation can support both directions. That support does not mean arbitrary page-number jumps are available. Design the interface around the operations the actual service exposes, including token expiry and any restrictions on changing filters.

Persist Records Before Advancing the Checkpoint

A checkpoint is useful only when it corresponds to durable output. Save the current page and its provenance before marking its next cursor as committed. Otherwise, a process that stops between those operations can resume beyond records that were never stored. Treat the checkpoint and output boundary as one application-level consistency problem.

A practical record envelope contains the source query, collection identity, requested sort, acquisition time, record identity, and continuation state. Keep credentials outside that envelope. When a token expires, retain the completed output and follow the documented restart path. Deduplication by stable record identity can protect the destination from repeated observations, but it cannot recover an item that was never observed.

Apply the Model to Browser Pagination

Browser pagination requires discovering the real continuation mechanism behind the interface. A numbered control may change a URL, submit a form, update a JSON request, or append records to the DOM. A visually identical Next button can represent a different mechanism on another site. Establish which action changes the underlying record set before automating the page.

Scrapeless Agent Browser supplies the browser layer when navigation requires rendered controls. It does not convert an offset-based website into a snapshot API. The pagination acquisition patterns cover numbered pages, next links, and scrolling. Keep source navigation state distinct from your destination checkpoint, especially when the browser displays records already collected.

Separate Page Completion from Collection Completion

A completed page is evidence about one response, while a completed collection is a claim about the traversal contract. An empty DOM region can mean loading is incomplete, a filter changed, or the source actually has no records. Validate the expected page identity and collection container before treating absence as the end.

For a browser run, capture the active filter and sort alongside the final observed record identities. For an API run, preserve the documented terminal continuation state. If the source provides a total count, determine whether it belongs to the same snapshot and filters. A changing headline count is useful context, but it should not override an authoritative continuation signal.

Choose by Navigation and Consistency Requirements

Choose offset pagination when users need direct numbered access and the collection is bounded enough to support it. Choose a documented keyset cursor design when sequential traversal over a large changing collection is the main workload. If you consume an existing service, adapt to its contract rather than relabeling its mechanism to match a preferred architecture.

For a new API, write down whether records can change sort positions, whether cursors expire, and whether readers need historical consistency. A browsing interface and an accounting export may need different endpoints. Offset vs cursor pagination is therefore a product decision as well as a query decision: the correct answer depends on the user operation you promise.

Validate a Traversal Before Scaling It

A traversal test should verify membership and boundaries, not only successful responses. Use a controlled dataset with duplicate sort values, missing optional fields, and edits between requests. Compare the collected identities with the intended set. Include a restart after an output write so the checkpoint behavior is exercised rather than merely described.

Measure page latency at different depths, output duplication, missing identities, and checkpoint storage cost. Keep hypothetical examples separate from production measurements. When browser acquisition is part of the design, consult the Agent Browser capability model and compare the relevant usage basis on Scrapeless pricing. More workers do not repair an ambiguous order or a broken completion rule.

Conclusion

Offset pagination fits direct access to positions; cursor pagination fits continuation through a collection. Start by fixing the ordering and defining the consistency requirement. Then test how inserts, deletions, token expiry, and interrupted writes affect the collected record set. A durable checkpoint and a documented completion signal matter more than the appearance of the pagination control.

Build Your Next Data Workflow

Use Scrapeless Agent Browser for the acquisition layer, and apply this comparison when designing the rest of your pipeline.

Sign up today and get $5 in free credit — no credit card required.

Claim Your $5 Credit →

FAQ

Q: Is cursor pagination always faster than offset pagination?

Cursor pagination is not always faster than offset pagination. An opaque token may wrap an offset or expensive server state. Performance depends on filters, indexes, sort order, query planning, and result depth. Compare the actual workload rather than treating the API parameter name as a benchmark.

Q: Does a cursor prevent all duplicates and missing records?

A cursor does not prevent every duplicate or missing record. Stable keyset boundaries address some position shifts, but mutable sort keys and changing collection membership can still affect traversal. Exact historical exports require a documented snapshot or another suitable consistency guarantee.

Q: Can cursor pagination support backward navigation?

Cursor pagination can support backward navigation when the API exposes that operation. The client usually needs the appropriate boundary token and direction parameters. Preserve the documented ordering; reversing the display order and changing the underlying query order are different operations.

Q: Should a scraper decode a returned cursor?

A scraper should treat a returned cursor as opaque unless the service explicitly documents its format for client use. Save it with the original filters and sort. Decoding a token for inspection does not establish that constructing or editing tokens is supported.

References