> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://contentful.com/developers/docs/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://contentful.com/_mcp/server. # React tutorial with Contentful > This guide to getting started with React explains how to connect a create-react-app application with Contentful's GraphQL API. The [JavaScript library React](https://reactjs.org/) is a popular tool to build interactive front end applications. Using the library, can deploy new React projects to any static hosting provider. This is great for performance and security, but also has a limitation: content often must be hardcoded in the application. To edit and update text or images, developers have to make code changes and redeploy the entire application. Luckily, React handles API data very well. To make content editable, you can bring in an API-driven content management system (CMS) like Contentful. Contentful's content platform is an excellent choice to untangle content and code to offer content creators ways to edit data without the need for a source code deploy. This guide to getting started with React explains how to connect a [create-react-app](https://reactjs.org/docs/create-a-new-react-app.html) application with [Contentful's GraphQL API](/references/graphql/overview). ## Prerequisite To follow this tutorial, you need: * a recent version of [Node.js](https://nodejs.org/) and npm available on your machine * a free [Contentful account](https://www.contentful.com/sign-up/) * a code editor ## Create a new React application The first thing is to bootstrap a new React application. Luckily, this use case is exactly why the [`create-react-app` npm package](https://www.npmjs.com/package/create-react-app) exists. Head over to your terminal and run the following commands: ```bash npx create-react-app my-app cd my-app npm start # or yarn start ``` `npx create-react-app` creates and bootstraps a new React project. It comes with a recommended React toolchain, follows best practices and is ready for development. To learn more about the setup, read [the official documentation](https://reactjs.org/docs/create-a-new-react-app.html). `npm start` starts a local development server. It supports hot reloading and source code linting to make React development as straightforward as possible. ```bash Compiled successfully! You can now view my-app in the browser. Local: http://localhost:3000 On Your Network: http://192.168.2.103:3000 Note that the development build is not optimized. To create a production build, use yarn build. ``` Open `localhost:3000` in your browser and find the `create-react-app` default screen. ![create-react-app starting screen](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/c20d75bc197c18b77aacc26296783ed06451998e4c1038aa24b381ed6dec1caf/docs/assets/images/react-tutorial-start-screen.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=9541bf23ce3c78139d39c62dd5140738881945256aed7450ac6f4be662b40e2f&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) Your application is now ready to be developed. Let's change it to use Contentful API data. ## Set up your Contentful space Using Contentful, you can tailor content structures and the connected API responses to your needs. In this tutorial, you will use and fetch a "Page" entry that holds the information of a title and a logo to replace the hardcoded values included in `create-react-app`. In Contentful, create and open a new Contentful space. Then create a new `Page` content type from the "Content model" section linked in the top navigation bar. !["Page" Content type defining a title and logo field](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/c7c58c058445934c233afbbfa9e6de147feca9ab817a346eb6cd2bd6d0cea343/docs/assets/images/react-tutorial-content-model.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=5616f17af577f200c6529ce7c86af7046f26ee2498e6177daebd6c8fd16a3368&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) Ensure that the content type defines a `short text` field for the title and a `one file` media field to allow a file upload for the logo. Once you created the content type, you can create multiple entries with the defined structure that includes a title and a logo field. Now, head to the "Content" section and create a new "Page" entry. !["Page" entry with a defined title and upload Contentful logo](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/7e40603a0ba7cd0584b2daf068a81cf28945f865de2bcd6bbf9ff8aa9bdd4f2d/docs/assets/images/react-tutorial-content-entry.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=3259a342bf5154c6d2665151916d2e046aa91a426719485e8f811ac7ee721347&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) Fill the fields with your preferred data and publish the entry. You are now ready to fetch this entry from within the React application. ## Fetch your content using GraphQL To fetch the data stored in Contentful, you can use RESTful APIs ([Content Delivery API](/references/content-delivery-api/overview), [Content Management API](/references/content-management-api/overview) and [Content Preview API](/references/content-preview-api/overview)) or [the GraphQL API](/references/graphql/overview). This tutorial uses the GraphQL API. [The main advantage of GraphQL](https://graphql.org/) is that developers can request and define the data included in the response. Additionally, GraphQL endpoints are self-documenting, and there is no need to install additional tooling or SDKs. ### Explore Contentful's GraphQL endpoint using GraphiQL To find out what data is available via the GraphQL endpoint, [Contentful provides GraphiQL](/references/graphql/exploring-the-schema-with-graphiql). GraphiQL is an in-browser tool that allows you to write GraphQL queries and explore the available data and schema. [We need to authenticate the made requests](/references/graphql/overview#authentication) and provide an access token before we can use GraphiQL or the GraphQL API. Head to the API keys section in the Contentful UI (top-level navigation -> Settings -> API keys) and copy your Space ID and Content Delivery API access token. ![API keys section in the Contentful UI](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/190db5be42ab16217e8f7ad71b2f81d8b59ae04b92fbf3eda98b35677f370390/docs/assets/images/react-tutorial-api-keys.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=ac77c0674961abe487ae1dab1320d0c95fab975353a13ab7d152af1e71fe14b1&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) With the Space ID and access token at hand, add these to the following URL and open GraphiQL in your browser: `https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/explore?access_token=[YOUR_ACCESS_TOKEN]` > **Info** > > Contentful's GraphQL API allows authentication via an `access_token` query parameter or an `Authorization` HTTP header. ### Write your first GraphQL query Now, use GraphiQL to write and define your GraphQL query. The tool allows you to make authenticated requests within its UI. Additionally, you can find the GraphQL schema documentation on the right side of the interface and you can write GraphQL queries with handy auto-completion. ![GraphiQL interface showing the documentation and a possible GraphQL query](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/37f7655f0ebd8f29dfd6e20d6eb7cf11c396749647ca15c16a97c3252acfabe4/docs/assets/images/react-tutorial-graphiql.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=c495076098918c501b29f96741236ac109fcadea8a7f50bc4f8f65d3c4490b0d&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) Depending on your defined content model, the GraphQL API provides queryable fields. To query a single "Page" entry with an id, use `page(id)`, or query a collection of pages using the `pageCollection` field. ![GraphiQL interface showing fields for a single and collection page field](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/7c44a8864536d20c815fca3f30e3a199f764b97ee9beaabb1bb67910fbf04fd7/docs/assets/images/react-tutorial-available-fields.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=0e5e5486c56e4d3c359a05356241af4c79c3d1c36d2020d4cc09b2794e0d8819&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) For simplicity, this tutorial uses the queryable collection field. To fetch a collection of pages use the following query to retrieve the `title` and `logo` for every entry. ``` { pageCollection { items { title logo { url } } } } ``` > **Info** > > In this tutorial the "Page" content type only includes two fields. Content model changes like field addition or deletions are reflected in the GraphQL schema and are available after saving the content type. With this query you can move on and start fetching data from within the created React application. ### Use Contentful GraphQL in your React application The main component in your bootstrapped React application is `App.js`. Let's edit the included functional component and bring in the Contentful data. The provided component includes hardcorded data and has the following structure: ```javascript function App() { // let's fetch Contentful data! return (
`
` logo

Edit src/App.js and save to reload.

Learn React `
`
); } ``` Copy and paste the working GraphQL query into the file and define a new `query` variable on top of the `App` function. ```javascript const query = ` { pageCollection { items { title logo { url } } } } ` ``` To make requests and connect functional React component to a particular state, add an import statement at the beginning of the file to import the React hooks `useState` and `useEffect`. ```javascript import {useState, useEffect} from "react"; ``` Go into `App` and define some initial state using `useState`. ```javascript function App() { // define the initial state const [page, setPage] = useState(null); // show a loading screen case the data hasn't arrived yet if (!page) { return "Loading..."; } // return statement and JSX template. // ... } ``` `useState` allows you to define an initial state value. It returns the current value and a setter method for the specified data. Every time you call the returned setter (`setPage` in this case) React rerenders the functional component. At this stage, the React application always shows a loading message because you're not fetching any data yet. To retrieve the page entry stored in Contentful, use `useEffect` to perform a request and set the returned data using `setPage`. > **Info** > > While we recommend using an advanced GraphQL client-side library for complex applications, the cross-browser-supported [`window.fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) method provides all the functionality you need for this tutorial. Define the URL endpoint (`https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/`) as the first function argument and pass in headers and additional configuration. ```javascript function App() { const [page, setPage] = useState(null); useEffect(() => { window .fetch(`https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/`, { method: "POST", headers: { "Content-Type": "application/json", // Authenticate the request Authorization: "Bearer [YOUR_ACCESS_TOKEN]", }, // send the GraphQL query body: JSON.stringify({ query }), }) .then((response) => response.json()) .then(({ data, errors }) => { if (errors) { console.error(errors); } // rerender the entire component with new data setPage(data.pageCollection.items[0]); }); }, []); if (!page) { return "Loading..."; } // return statement and JSX template. // ... } ``` > **Info** > > A detailed explanation of `useState` and `useEffect` is not part of this tutorial. To learn more about this React functionality, read [the official React documentation](https://reactjs.org/docs/hooks-intro.html), or watch the official React documentation. With the addition of `window.fetch` called in `useEffect` the `App` component fetches GraphQL data from Contentful. But it is not rendering it yet. The last step is to update the returned JSX template to use the data. Change the logo URL and the hardcoded text to use `page.title` and `page.logo.url`. The final state of your Contentful-connected React component now looks as follows: ```javascript import { useState, useEffect } from "react"; import "./App.css"; const query = ` { pageCollection { items { title logo { url } } } } `; function App() { const [page, setPage] = useState(null); useEffect(() => { window .fetch(`https://graphql.contentful.com/content/v1/spaces/[YOUR_SPACE_ID]/`, { method: "POST", headers: { "Content-Type": "application/json", Authorization: "Bearer [YOUR_ACCESS_TOKEN]", }, body: JSON.stringify({ query }), }) .then((response) => response.json()) .then(({ data, errors }) => { if (errors) { console.error(errors); } setPage(data.pageCollection.items[0]); }); }, []); if (!page) { return "Loading..."; } // render the fetched Contentful data return (
`
` logo

{page.title}

`
`
); } export default App; ``` ## Summary In this tutorial, you learned how to create a new content type, how to create an entry of this type and fetch it from within a new React application using GraphQL. The application data is now editable from Contentful's UI, and you replaced the hardcoded React logo and message with dynamic API data. ![The final version of create-react-app with Contentful data](https://fdr-prod-docs-files-public.s3.us-east-1.amazonaws.com/contentful.docs.buildwithfern.com/9470ec11bd600eb28555e4dd824296674170ff4a0663471a4e3edbf5f201fb22/docs/assets/images/react-tutorial-final-state.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIA6KXJSKKNFOCF7G4B%2F20260929%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260929T222549Z&X-Amz-Expires=604800&X-Amz-Signature=282159bd0df73ff82bec8c26f6ad4f60a9b21535dc0e7df063eaf22af5e1e598&X-Amz-SignedHeaders=host&x-amz-checksum-mode=ENABLED&x-id=GetObject) ## Next steps * [Read the Contentful GraphQL API documentation](/references/graphql/overview) * [Install the GraphQL playground app and use GraphQL tooling in the Contentful UI](https://www.contentful.com/marketplace/app/graphql-playground/) > This guide to getting started with React explains how to connect a create-react-app application with Contentful's GraphQL API.