Integrate external data
Fetch external data in bricks
Fetch data directly inside a brick with getExternalData and merge the API response into the brick props.
In this how-to, you'll learn how to fetch data from an external API directly inside a brick.
This is the simplest way to integrate external data in React Bricks when a single brick is responsible for rendering that data.
This fetching happens server-side. In Next.js App Router projects, React Bricks does this by leveraging Server Components.
That means:
- the external API call is not exposed in the browser
- the fetched content is already present in the rendered HTML, which is better for SEO
- users see the final content immediately, without waiting for a client-side fetch after page load
Docs reference: Get data from external APIs
When brick-level fetching is a good fit
Fetching inside a brick works well when:
- only one brick needs the external data
- the request depends on that brick's own props
- you want the brick to stay self-contained
For example, a brick may:
- fetch a Pokemon chosen in the sidebar
- load product data using a
productIdstored on the page - call a third-party API based on a slug or other page value
If several bricks need the same external data, fetching at page type level is usually a better choice. We'll cover that in the next guide.
Use getExternalData on the brick schema
To fetch external data in a brick, add a getExternalData function to the brick's schema.
This function is async and should return an object.
React Bricks merges that returned object into the brick props, so the fetched data becomes available inside the component.
The function receives:
page: the current page objectbrickProps: the current props for that brickargs: optional extra arguments passed fromfetchPage
Docs reference: Connect external APIs
The TypeScript signature is:
getExternalData?: (
page: Page,
brickProps?: T,
args?: any
) => Promise<Partial<T>>Example: fetch data from a brick prop
Let's create a Pokemon brick.
The editor chooses a Pokemon name in the sidebar, and the brick fetches the data from the public Pokemon API.
This is a nice example for a how-to because it works without any API key.
import React from 'react'
import { types } from 'react-bricks/rsc'
interface PokemonProps {
pokemonName: string
id: number
name: string
height: number
weight: number
imageUrl: string
}
const Pokemon: types.Brick<PokemonProps> = ({
id,
name,
height,
weight,
imageUrl,
}) => {
if (!id || !name || !height || !weight || !imageUrl) {
return null
}
return (
<div className="my-6 pb-6 container max-w-3xl mx-auto border-2 border-slate-200">
<div className="p-2 bg-slate-100 mb-6">
<p className="text-sm text-slate-700 uppercase tracking-widest font-bold text-center mb-1">
Test external data
</p>
</div>
<img src={imageUrl} className="mx-auto w-36 mb-4" />
<h1 className="text-5xl font-extrabold text-center mb-6">{name}</h1>
<p className="text-center">
#{id} - Height {height / 10} m - Weight {weight / 10} Kg
</p>
</div>
)
}
Pokemon.schema = {
name: 'pokemon',
label: 'Pokemon',
previewImageUrl: `/bricks-preview-images/pokemon.png`,
getDefaultProps: () => ({
pokemonName: 'pikachu',
}),
getExternalData: (page, brickProps) =>
fetch(`https://pokeapi.co/api/v2/pokemon/${brickProps?.pokemonName}`)
.then((response) => response.json())
.then((data) => ({
id: data.id,
name: data.name,
height: data.height,
weight: data.weight,
imageUrl: `https://img.pokemondb.net/artwork/large/${data.name}.jpg`,
}))
.catch(() => {
return {
id: 0,
name: '',
height: 0,
weight: 0,
imageUrl: '',
}
}),
sideEditProps: [
{
name: 'pokemonName',
label: 'Pokemon Name',
type: types.SideEditPropType.Text,
helperText:
'Enter a valid Pokemon name, like "pikachu" or "charizard" and save.',
},
],
}
export default PokemonHere is what happens:
- the editor sets the
pokemonNameprop in the sidebar getExternalDatareadsbrickProps.pokemonName- the API response is transformed into the props the brick needs
- the fetched values are merged into the brick props
- the component renders the fetched values
This pattern is very useful when the request depends on a value chosen per brick instance.
If you want to see an authenticated external API example, the official docs also show a stock quote example: Connect external APIs
Example: fetch data from a page custom field
Sometimes the API request should be based on a page-level value rather than a brick prop.
For example, a product page type may have a custom field called productId.
In that case, the brick can read the value from page.customValues.
Product.schema = {
name: 'product',
label: 'Product',
getExternalData: async (page) => {
const response = await fetch(
`https://example.com/api/products/${page.customValues.productId}`
)
const product = await response.json()
return {
productName: product.name,
productImage: product.imageUrl,
}
},
}This works well when:
- the external record belongs to the page as a whole
- the page type stores a stable identifier such as
productId - one brick is responsible for rendering that external data
If you haven't added page custom fields yet, see: Add custom fields
A note about args
The third argument of getExternalData is args.
You can use it to receive additional values passed from fetchPage, such as query string parameters, or other request-time context.
That can be helpful when the external API call depends on runtime input instead of only page values or brick props.
For a complete real-world example of using args with dynamic route params, see:
Generate pages from a visual template and external data
Tips for production use
When integrating real APIs, it helps to keep a few things in mind:
- return only the fields the brick actually needs
- handle missing or invalid API responses gracefully
- avoid exposing secrets directly in client-side code
- use caching or revalidation when your framework supports it
In the example above, { next: { revalidate: 10 } } is a Next.js caching option that lets you refresh the external data periodically instead of fetching on every request.
This server-side approach is especially useful for SEO-sensitive content, because search engines receive the fetched content as part of the initial HTML response.
When to move fetching to page level
Brick-level fetching is the easiest approach, but it is not always the best one.
If multiple bricks on the same page need the same external response, fetching once at page type level is often cleaner and more efficient.
In that case, the page type performs the fetch and each brick maps the shared external data to its own props.
We'll use that approach in the next guide.