Integrate external data
Fetch external data in page types
Fetch external data once at page type level and map the shared result to brick props with mapExternalDataToProps.
In this how-to, you'll learn how to fetch external data at page type level and use it inside bricks.
This approach is useful when multiple bricks on the same page need access to the same external data.
Instead of making each brick fetch independently, the page type fetches the data once, and each brick maps the part it needs into its own props.
Like brick-level external data, this fetching happens server-side.
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
- multiple bricks can reuse the same data without duplicating requests
Docs reference: Get data from external APIs
When page-type fetching is a good fit
Fetching at page type level works well when:
- multiple bricks need the same external response
- the data belongs to the page as a whole
- you want to centralize the API call in one place
This is common for pages such as:
- product pages, where several bricks need product data
- event pages, where multiple sections use the same event record
- destination or listing pages, where several bricks depend on shared API data
In these cases, fetching once at page level is usually cleaner and more efficient than letting each brick call the API separately.
Use getExternalData on the page type
To fetch data at page level, define getExternalData on the page type.
The function receives the current page and can also receive args, just like in the brick-level version.
It should return a promise that resolves to an object containing the external data for that page.
Docs reference: Page Types
The signature is:
getExternalData?: (page: Page, args?: any) => Promise<Props>The arguments are:
page: the current page objectargs: optional extra arguments passed fromfetchPage, for example to receive a query string parameter
Example: fetch product data in the page type
Let's imagine a product page type with a custom field called productId.
The page type can use that productId to fetch product data once for the whole page.
import { types } from 'react-bricks/rsc'
const pageTypes: types.IPageType[] = [
{
name: 'product',
pluralName: 'products',
defaultStatus: types.PageStatus.Published,
customFields: [
{
name: 'productId',
label: 'Product ID',
type: types.SideEditPropType.Text,
},
],
getExternalData: async (page, args) => {
const response = await fetch(
`https://example.com/api/products/${page.customValues.productId}`
)
const product = await response.json()
return {
productName: product.name,
productDescription: product.description,
productImage: product.imageUrl,
productPrice: product.price,
}
},
},
]
export default pageTypesHere the fetch happens once for the page, and the returned object becomes the page-level external data.
If you haven't added page custom fields yet, see: Add custom fields
Use mapExternalDataToProps in a brick
Once the page type fetches the external data, a brick can read that shared data through mapExternalDataToProps.
This function belongs to the brick schema.
It receives:
- the external data fetched at page level
- the current brick props
It should return an object that React Bricks merges into the brick props.
Docs reference: Use data fetched at Page level
The signature is:
mapExternalDataToProps?: (externalData: Props, brickProps?: T) => Partial<T>Example: map page-level product data into a brick
Let's say we have a brick that renders a product hero.
In this version, the title is visually editable with a Text component.
If the editor writes a custom title, that title overrides the external data.
If the editor clears the title, the brick falls back to externalData.productName.
import { Text, types } from 'react-bricks/rsc'
interface ProductHeroProps {
title: types.TextValue
price?: number
image?: string
}
const hasTextValueContent = (value?: types.TextValue) => {
if (!value || !Array.isArray(value)) return false
return value.some((node: any) =>
Array.isArray(node.children) &&
node.children.some(
(child: any) => typeof child.text === 'string' && child.text.trim() !== ''
)
)
}
const ProductHero: types.Brick<ProductHeroProps> = ({
title,
price,
image,
}) => {
return (
<section>
<Text
propName="title"
value={title}
placeholder="Product title..."
renderBlock={({ children }) => <h1>{children}</h1>}
/>
{typeof price === 'number' ? <p>Price: ${price}</p> : null}
{image ? <img src={image} alt="" /> : null}
</section>
)
}
ProductHero.schema = {
name: 'product-hero',
label: 'Product Hero',
mapExternalDataToProps: (externalData, brickProps) => ({
title: hasTextValueContent(brickProps?.title)
? brickProps?.title
: externalData.productName,
price: externalData.productPrice,
image: externalData.productImage,
}),
}
export default ProductHeroNotice that the title check is not just brickProps?.title.
That is important because TextValue is a Slate data structure, so it may still be truthy even when the editor has cleared the text.
That is why the example uses hasTextValueContent to check whether the editable value really contains text before deciding whether to override the external data.
Here is what happens:
- the page type fetches the external data once
mapExternalDataToPropsreceives that shared data- the brick selects the values it needs
- those values are merged into the brick props before rendering
This gives each brick a very simple API, while keeping the actual fetch logic centralized at page level.
Why mapExternalDataToProps is useful
mapExternalDataToProps lets each brick decide how to consume the shared external data.
For example:
- one brick may use
productNameas a title - another may use
productDescription - another may show only
productPrice
Each brick maps the same shared external object into its own prop shape.
That means the page type owns the fetch, while each brick owns its presentation logic.
A note about args
Just like the brick-level version, page-type getExternalData also accepts args.
You can use args to receive additional values passed from fetchPage, such as query string parameters or other request-time context.
That is useful when the external API request depends not only on the page itself, but also on runtime input.
For a complete real-world example of using args with dynamic route params, see:
Generate pages from a visual template and external data
When to choose page types vs bricks
Use brick-level fetching when one brick needs its own independent external data.
Use page-type fetching when the data belongs to the page and should be shared across multiple bricks.
Both approaches are valid, but page-type fetching is usually the better option when you want to avoid repeated API calls and keep shared external data centralized.