Fetch third-party API data with Hydrogen
Hydrogen includes a built-in client and utilities for fetching data with Shopify's Storefront API and Customer Account API.
If you need to access data from third-party sources, then you can re-use these utilities and design patterns. By consistently using the same methods for data fetching regardless of the source, your app logic is simpler to understand, and your app will be more performant.
Anchor to What you'll buildWhat you'll build

In this guide, you'll use Hydrogen's built-in utilities to query the GraphQL Rick and Morty API and display a list of characters.
This simplified example shows how to re-use Hydrogen tools to create a new API client, add it to the Remix context, and query your data from any route.
Anchor to Step 1: Create a new third-party API clientStep 1: Create a new third-party API client
The following example re-uses existing Hydrogen utilities to create an API client that handles caching with the same tooling and method that Hydrogen uses for Shopify API queries. This keeps data fetching and caching behaviors consistent across your app.
Create a third-party API client
/app/lib/createRickAndMortyClient.server.js
import {createWithCache, CacheLong} from '@shopify/hydrogen';
export function createRickAndMortyClient({
cache,
waitUntil,
request,
}) {
const withCache = createWithCache({cache, waitUntil, request});
async function query(
query,
options = {variables: {}, cacheStrategy: CacheLong()},
) {
const result = await withCache.fetch(
'https://rickandmortyapi.com/graphql',
{
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
query,
variables: options.variables,
}),
},
{
cacheKey: ['r&m', query, JSON.stringify(options.variables)],
cacheStrategy: options.cacheStrategy,
shouldCacheResponse: (body) =>
body.error == null || body.error.length === 0,
},
);
return result.data;
}
return {query};
}
import {createWithCache, CacheLong, type CachingStrategy} from '@shopify/hydrogen';
export function createRickAndMortyClient({
cache,
waitUntil,
request,
}: {
cache: Cache;
waitUntil: ExecutionContext['waitUntil'];
request: Request;
}) {
const withCache = createWithCache({cache, waitUntil, request});
async function query<T = any>(
query: `#graphql:rickAndMorty${string}`,
options: {
variables?: object;
cacheStrategy?: CachingStrategy;
} = {variables: {}, cacheStrategy: CacheLong()},
) {
const result = await withCache.fetch<{data: T; error: string}>(
'https://rickandmortyapi.com/graphql',
{
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify({
query,
variables: options.variables,
}),
},
{
cacheKey: ['r&m', query, JSON.stringify(options.variables)],
cacheStrategy: options.cacheStrategy,
shouldCacheResponse: (body: {data: T; error: string}) =>
body.error == null || body.error.length === 0,
},
);
return result.data;
}
return {query};
}
Anchor to Step 2: Create the API client and pass to the Remix contextStep 2: Create the API client and pass to the Remix context
You can now add your API client to the app's context file so it's available to load data from your routes.
Pass API client to Remix context
/app/lib/context.js
// ...Existing context.js imports here...
import {createRickAndMortyClient} from './app/lib/createRickAndMortyClient.server';
export async function createAppLoadContext(
request: Request,
env: Env,
executionContext: ExecutionContext,
) {
// ... Existing context creation code here...
// Create the Rick and Morty API Client
const rickAndMorty = createRickAndMortyClient({
cache,
waitUntil,
request,
});
return {
...hydrogenContext,
rickAndMorty,
};
};
// ...Existing context.ts imports here...
import {createRickAndMortyClient} from './app/lib/createRickAndMortyClient.server';
export async function createAppLoadContext(
request: Request,
env: Env,
executionContext: ExecutionContext,
) {
// ... Existing context creation code here...
// Create the Rick and Morty API Client
const rickAndMorty = createRickAndMortyClient({
cache,
waitUntil,
request,
});
return {
...hydrogenContext,
rickAndMorty,
};
};
Anchor to Step 3: Query and render the list of entriesStep 3: Query and render the list of entries
You can now query your rickAndMorty
API client from any loader function, on any route, using the same caching utilities that Hydrogen uses to query Shopify's Storefront API.
The following simplified example shows how to render an unordered list of character names on the /characters
route:
Render character index route
/app/routes/characters._index.jsx
import {json} from '@shopify/remix-oxygen';
import {useLoaderData} from '@remix-run/react';
import {CacheShort} from '@shopify/hydrogen';
// Fetch and return API data with a Remix loader function
export async function loader({context}) {
const {characters} = await context.rickAndMorty.query(CHARACTERS_QUERY, {
cache: CacheShort(),
});
return json({characters});
}
// Render the component using data returned by the loader
export default function Characters() {
const {characters} = useLoaderData();
return (
<div>
<h1>Rick & Morty Characters</h1>
<ul>
{(characters.results || []).map((character) => (
<li key={character.name}>{character.name}</li>
))}
</ul>
</div>
);
}
// Query the API for a list of characters
const CHARACTERS_QUERY = `#graphql:rickAndMorty
query {
characters(page: 1) {
results {
name
id
}
}
}
`;
import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
import {useLoaderData} from '@remix-run/react';
import {CacheShort} from '@shopify/hydrogen';
// Fetch and return API data with a Remix loader function
export async function loader({context}: LoaderFunctionArgs) {
const {characters} = await context.rickAndMorty.query(CHARACTERS_QUERY, {
cache: CacheShort(),
});
return json({characters});
}
type Character = {
name: string;
id: string;
};
// Render the component using data returned by the loader
export default function Characters() {
const {characters} = useLoaderData<typeof loader>();
return (
<div>
<h1>Rick & Morty Characters</h1>
<ul>
{(characters.results || []).map((character: Character) => (
<li key={character.name}>{character.name}</li>
))}
</ul>
</div>
);
}
// Query the API for a list of characters
const CHARACTERS_QUERY = `#graphql:rickAndMorty
query {
characters(page: 1) {
results {
name
id
}
}
}
`;
Run shopify hydrogen dev
to start the development server, then open http://localhost:3000/characters to verify that the query succeeded.
Anchor to Next stepsNext steps
- If you haven't already, learn about querying first-party Shopify APIs with Hydrogen
- Learn more about caching third-party API data with Hydrogen