
n8n HTTP Request pagination stops working for a handful of repeatable reasons, and almost all of them come down to the completion check. The default, Response Is Empty, only stops on an empty array or an empty body, so any API that returns {"data": []} on its last page keeps n8n requesting pages until something else stops it. Switch Pagination Complete When to Other and test the real signal: {{ $response.body.data.length === 0 }}, a missing next cursor, or $pageCount reaching the API's total pages.
The other eight causes are smaller, but they're behind most of the "it loops", "it duplicates" and "it threw away everything" threads on the n8n community forum. We tested every one of them.
How we tested n8n pagination
We didn't want to repeat forum advice, so we built a small local API in Python with 12 records at 5 per page. It served each pagination style we run into on real projects: a bare array, a wrapper object, a cursor with an absolute next URL, a relative next path, a Link header, an API that returns page 1 when you go past the end, and one that rate limits with a 429.
Then we generated 22 workflows (Manual Trigger plus one HTTP Request node, version 4.5) and ran each with n8n execute in Docker on n8n 2.47.7 (the current stable tag) and n8n 3.2.2. The API logged every request, so the counts below are real requests, not estimates. Both versions behaved identically in all 22 cases, so nothing here depends on whether you've upgraded to 3.x.
1. Why does "Response Is Empty" never stop?
Because "empty" means the whole body. n8n's check is literally: if the body is an array, continue while it has length; otherwise, continue while the body is truthy. An object like {"data": [], "page": 4, "total": 12} is truthy.
Limit Pages Fetched is off by default, so nothing caps it. Against our wrapper API, the default setup sent 301 requests for 12 records before our API refused to answer. A real API would keep answering, and you'd be burning quota, execution time and memory.
The fix is one setting. Set Pagination Complete When to Other and use:
- Most wrapper APIs:
{{ $response.body.data.length === 0 }}. Our test finished in 4 requests. - Better, if the API tells you the page size:
{{ $response.body.data.length < $response.body.per_page }}. This stops on the short last page and skips the empty request. 3 requests. - Cursor APIs:
{{ !$response.body.next_cursor }}, or whatever field holds the next value.
Replace data with whatever your API calls the list (results, items, records).
2. What does "The returned response was identical 5x" mean?
It's n8n's built-in loop guard. Each response is hashed and compared with the previous one, and after five byte-identical responses in a row the node throws The returned response was identical 5x, so requests got stopped.
It saved us from infinite loops in several tests, but read the fine print: when it fires, the node fails and outputs none of the pages it already fetched. In our test of a wrapper API that returns a static {"data": []}, n8n fetched the 3 real pages plus 5 empty ones, then threw the lot away.
When you see this error, the completion check is wrong or the page value isn't changing. Causes 3, 4 and 5 below are the usual culprits.
3. Does $pageCount start at 0 or 1?
At 0, and this catches a lot of people. The pagination parameter is applied to the first request too, not just the follow-ups. With page set to {{ $pageCount }}, n8n sent page=0, 1, 2, 3, 4.
Our API, like many real ones, treats page 0 as page 1. The result was 17 items for 12 records: page 1 came back twice and nothing errored. Duplicates like that slide straight into a CRM or a Google Sheet.
For 1-based APIs use {{ $pageCount + 1 }}. For offset APIs use {{ $pageCount * 100 }} with your page size. Inside the completion expression, $pageCount already counts the page you just received, so {{ $pageCount >= $response.body.total_pages }} is correct as written.
4. Why does it keep fetching page 1?
A common reason: the page number is in two places. Someone pasted https://api.example.com/items?page=1 into the URL field and also added page as a pagination parameter.
n8n doesn't replace the one in the URL. It sends both. Our API received page=1&page=2, page=1&page=3 and so on, read the first value, returned page 1 every time and hit the identical-response guard after 5 requests.
Remove page (or offset, cursor, after) from the URL and from Query Parameters. The pagination option should be the only place it's set.
5. What if the API returns the first page when you go past the end?
Some APIs never return an empty page. Ask for page 4 of 3 and you get page 1 again. An emptiness check can't work there. In our test it requested pages 1 through 8, then died on the identical-response guard with no output.
Use the API's own totals instead:
- Total pages in the body:
{{ $pageCount >= $response.body.total_pages }}. 3 requests, all 12 records, no error. - Total records only:
{{ $pageCount * 100 >= $response.body.total }}with your page size. - A has_more flag:
{{ !$response.body.has_more }}.
6. Why does Next URL say "is not a valid URL"?
Because the API gave you a relative path. Our cursor API returned next_path: "/items?cursor=5" and n8n failed on the first follow-up with '/…/items?cursor=5' is not a valid URL. The Next URL has to be absolute.
Build it from the original request:
{{ $request.uri.split('/').slice(0,3).join('/') + $response.body.next_path }}
That worked: 3 requests, all pages. Two things that look like they should work didn't. new URL($response.body.next_path, ...) and $request.url both evaluated to nothing without any error. n8n then silently re-requested the original URL until the identical-response guard stopped it. If your Next URL "works" but you only ever get page 1, check whether the expression is actually producing a URL.
7. Can the built-in pagination follow a Link header?
Yes, despite the forum threads saying you need a manual loop. GitHub-style APIs put the next page in a Link response header, and $response.headers is available in the pagination expressions:
- Pagination Mode: Response Contains Next URL
- Next URL:
{{ $response.headers.link?.match(/<([^>]+)>;\s*rel="next"/)?.[1] }} - Pagination Complete When: Other,
{{ !/rel="next"/.test($response.headers.link ?? '') }}
Our test fetched 3 pages and returned all 12 records as separate items. The regex matters: Link headers usually list next, last and sometimes prev, so match rel="next" specifically.
8. Why did one 429 throw away every page?
Pagination runs inside one node execution, so one failed page fails the node and discards the pages already fetched. Our rate-limited API returned 429 when requests came less than 400 ms apart. With default settings, page 2 got a 429 and the node output nothing.
Retry On Fail doesn't rescue this. It re-runs the whole node, so our log showed page=1, page=2, page=1, page=2, page=1, page=2: three tries, three failures, page 1 downloaded three times.
The fix is in the pagination options: Interval Between Requests (ms). At 600 ms the same API returned all 12 records in 4 requests and about 2 seconds. Set it from the API's documented limit with some headroom. For per-minute quotas or limits shared across workflows, our n8n 429 rate limit guide covers the patterns that hold up.
9. Why do I get one item per page instead of one per record?
If the API returns a bare array, n8n splits it into one item per record for you. If it returns a wrapper object, you get one item per page. Our wrapper test returned 4 items for 12 records, each holding a data array.
Add a Split Out node on the list field (data here) right after the HTTP Request node. Ours went from 4 items to 12. Skip it and the next node runs once per page, which is how people end up "missing" records that were there all along.
Should you turn on Limit Pages Fetched?
Yes, but treat it as a safety net, not a stop condition. When Max Pages is reached, n8n stops quietly. No error, no warning. With a cap of 10 on our runaway wrapper test, it returned 10 pages and moved on as if that were everything.
Our rule: the completion expression ends the loop, and Max Pages sits at roughly double the largest page count you expect. If a run ever hits the cap, something changed in the API. Compare the record count to the API's total in an IF node and alert on a mismatch. Our guide to n8n error handling and monitoring shows how we route those alerts.
Our pagination checklist
This is the order we debug pagination in:
- Look at one raw page with pagination off. Note the shape of the last page: array or object, next cursor, next URL, Link header, total pages.
- Fix the first request:
{{ $pageCount + 1 }}for 1-based APIs, and no page parameter left in the URL. - Write a completion check that matches the API (cause 1 or 5), never the default on wrapper APIs.
- Make next URLs absolute and confirm the expression returns a value.
- Add Interval Between Requests if the API has any rate limit.
- Set Max Pages as a safety net and Split Out the list field.
If a sync still hangs after that, the execution itself may be stuck. Our stuck n8n execution guide covers that side. n8n's own pagination cookbook has worked examples of each mode. Just keep the completion-check caveat above in mind when you copy them.
Pagination also trips up teams moving over from other platforms, because Zapier and Make handle paging inside their app modules. If you're migrating, our Zapier and Make to n8n migration guide lists the other gaps to plan for.
Get a free automation audit
If your n8n syncs are pulling duplicates, stopping at page one or quietly missing records, we can review them with you. We check each paginated call against the API's real behavior and flag loops, silent caps and lost pages before they reach your CRM. Get a Free Automation Audit and we'll email your initial report within 24 hours, or see how we build production workflows on our n8n workflow automation page.
