I’m working on pulling customer information from my Shopify store through their API using Laravel PHP. My store has over 6000 customers, but my current implementation only returns 250 records instead of the full dataset. I suspect there’s an issue with how I’m handling pagination. Here’s my current approach:
public function getAllStoreCustomers($storeId)
{
// Get store configuration
$storeConfig = DB::table('shopify_connections')
->select('domain', 'id', 'token')
->where('owner_id', Auth::user()->id)
->where('id', $storeId)
->first();
if (!$storeConfig) {
return redirect()->back()->withErrors(['message' => 'Store configuration not found']);
}
$allCustomers = collect();
$apiEndpoint = "/admin/api/2025-01/customers.json";
$requestParams = ['limit' => 250];
do {
$apiResponse = self::makeShopifyRequest(
$storeConfig->token,
$storeConfig->domain,
$apiEndpoint,
$requestParams,
'GET'
);
$responseData = json_decode($apiResponse['response'], true);
$responseHeaders = $apiResponse['headers'];
if (isset($responseData['customers']) && is_array($responseData['customers'])) {
$allCustomers = $allCustomers->merge($responseData['customers']);
}
sleep(1); // Rate limiting
$apiEndpoint = $this->extractNextPageLink($responseHeaders);
$requestParams = [];
} while ($apiEndpoint);
return view('shopify.customer_list', ['customers' => $allCustomers->toArray()]);
}
private function extractNextPageLink($headers)
{
if (isset($headers['link'])) {
preg_match('/<(.*?)>; rel="next"/', $headers['link'], $linkMatches);
return $linkMatches[1] ?? null;
}
return null;
}
Can anyone spot what might be preventing the pagination from working correctly?
Your Link header extraction is probably the culprit. I’ve hit this same issue when headers come back as arrays instead of strings. First thing - dump your actual $responseHeaders structure to see what you’re working with. Sometimes the ‘link’ key is capitalized differently or nested weird depending on your HTTP client. Your regex assumes a specific format, but Shopify often returns multiple rel links. Skip the regex and split on commas instead, then check each link part separately. Also watch out for HTTP libraries that lowercase header names - check for both ‘link’ and ‘Link’. One more gotcha: make sure $apiEndpoint in your loop has the full URL with domain. If extractNextPageLink only returns the path, you’ll need to rebuild the complete endpoint. I’ve seen cases where the next page URL gets mangled during extraction and kills the loop early.
Had the same pagination nightmare with Shopify’s API last year. Your extractNextPageLink method is probably the culprit - Shopify’s Link header format is a pain to parse and that regex might not catch all the variations. I ditched the Link header parsing entirely and switched to cursor-based pagination. Just use the since_id parameter with the last customer ID from each batch: $requestParams['since_id'] = end($responseData['customers'])['id']; before the next loop. Way more reliable than regex and handles Shopify’s weird pagination quirks. Also check that your makeShopifyRequest method actually returns headers in the right format. Some HTTP clients mess with header names, which breaks Link header parsing.
Check if your makeShopifyRequest method returns headers correctly. I’ve seen HTTP clients format headers weird and break pagination. Also log the extracted next page URL - sometimes the regex works but you get an incomplete URL or missing domain that kills the loop.
The problem’s probably in how your HTTP client handles requests with the extracted pagination URL. I hit the same issue - Link header parsing worked fine, but follow-up requests weren’t authenticating properly. When you pull the next page URL from the Link header, it’s a complete Shopify URL with query parameters. If your makeShopifyRequest method adds auth headers or tokens in a specific way, passing it a full URL instead of just the endpoint path might break things. Log the HTTP response codes for each pagination request - you’re probably getting 401s or 403s after the first call works. Also check that your makeShopifyRequest method handles full URLs and relative paths the same way. Sometimes these methods expect to build the complete URL themselves and get confused when you feed them a pre-built URL from the Link header.
Your pagination loop looks good, but there’s an issue with the endpoint variable. When you extract the next page link and assign it to $apiEndpoint, you’re overwriting the entire path. The problem? extractNextPageLink returns a full URL from Shopify’s Link header, but makeShopifyRequest probably expects just the API path. This mismatch makes subsequent requests fail silently or return empty results, breaking your pagination. Don’t reassign the full URL to $apiEndpoint - parse it to extract only the path and query parameters. Also throw in some debugging output to check if each API response actually has customer data. You might be getting successful HTTP responses with empty customer arrays that kill your loop early.