How to create a product page using Odoo API in NextJs.

Hello friends. I am happy to help you write a blog post on how to create a product page using Odoo API in Next JS and how to use it to manage the product in NextJs using Odoo API help.
First, we will have a discussion about NextJS and start by presenting the concept of Odoo and its API.
What is NextJS?
Next Js is a full-stack web development framework. It is a free and open source react frontend library framework for building user interfaces based on UI components. NextJs Provides all the features needed to develop multiple types of websites and applications that can be created Static and server rendering, static side regeneration, Typescript support and routing.
Understanding the Odoo API.
Basically, Odoo API is normally the Rest API that provides the services of e-commerce products and acts as a bridge between your application and the Odoo platform. It provides the power to interact with your application through API and manipulate various elements such as products, customers, product orders and many more.
Real-world use cases.
Odoo company? Learn more
- E-commerce integration.
- Inventory management.
To start:-
- API endpoints: Odoo offers a range of API endpoints that allow you to perform different actions like ‘some products’, ‘category-list’, And ‘customer’ but we will work with the ‘product list’ period.
To retrieve product data, you will make a “GET” or “POST” request from the appropriate API endpoints to the appropriate API endpoints. But you would make a request to the “product list”. You can also filter and sort the data according to your needs.
Hope you have installed the next JS project, then you can see the project folder structure like this.
. ├── pages/ │ ├── api │ ├── hello.js │ ├── app.js │ ├── _document.js │ └── index.js ├── public/ │ ├── favicon.ico │ ├── next.svg │ └── vercel.svg ├── styles/ │ └── global.css ├── next.config.js ├── package-lock.json ├── package.json ├── postcss.config.js ├── README.md ├── tailwind.config.js └── tsconfig.js
Create the .env file in the root directory and we need to define some variables that are going to be used.
//------------.env--------------// MODE=PRODUCTION CLIENT_TOKEN=Authenticate_Token API_URL= API_VERSION=v1
Here we need to pass a token into Header to authenticate and use the Oddo API.
- We also need to set the environment variables in our next.config.js file, otherwise we won’t be able to use these variables at the frontend.
//------------next.config.js-----------// /** @type {import('next').NextConfig} */ const path = require('path'); const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); const nextConfig = { env: { CLIENT_TOKEN: process.env.CLIENT_TOKEN, API_URL: process.env.API_URL, API_VERSION: process.env.API_VERSION, }, reactStrictMode: true, }; module.exports = withBundleAnalyzer(nextConfig);
Make sure you have the necessary API endpoints URL ‘product list’, authentication and other settings. we will have to use the fetch function or a library like Axios to retrieve data from the Odoo API.
- Create a route file to display the product:
We will create the file in the pages directory to display the product followed by the name (pages/product/(urlkey).js).
//---------------pages/product/(urlkey).js-----------// import Image from 'next/image'; import { useState } from 'react'; const Product = ({ product }) => { const { thumbnail, price_range, sku } = product; const (addtocart, setAddtocart) = useState(1); const add = () => { setAddtocart(addtocart + 1); }; const sub = () => { addtocart > 1 && setAddtocart(addtocart - 1); }; return ( <div class="grid grid-cols-5 gap-4 w-(85%) mx-auto my-5"> <div className="col-span-2 border border-1 border-solid border-slate-400 rounded"> <Image src={thumbnail?.id} width={500} height={500} /> </div> <div className="col-span-3 mx-10"> <div className=""> <div display="grid"> <p className="font-(500) text-(2.5rem)">{product.name || ''}</p> <div className="flex justify-between "> <p className="text-price" sx={{ paddingTop: 1.5 }}> <span className="font-semibold"> $ {price_range?.minimum_price?.regular_price?.value} </span> <s className="pl-4 italic font-light text-fadedText"> {price_range?.discount?.amount_off} </s> </p> <p variant="body1" className="mt-7"> Sku : {sku} </p> </div> <div className="flex"> <button onClick={sub} aria-label="increment" className="text-white w-10 rounded-l h-8 border-0 cursor-pointer bg-secondary hover:bg-brand hover:contrast-75" > - </button> <input max={6} type="text" className="relative w-14 border-(1px) border-gray flex items-center px-3 font-semibold text-center text-gray-700 outline-none cursor-default -z-10 readonly focus:outline-none text-md hover:text-black focus:text-black md:text-base" min={1} value={addtocart} id="quantity" placeholder="0" /> <button aria-label="increment" className="text-white w-10 h-8 rounded-r border-0 cursor-pointer bg-secondary hover:bg-brand hover:contrast-75" onClick={add} > + </button> </div> <p className="pt-3 text-hoverEffect text-(16px) "> {product.short_description?.html || 'Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sunt reprehenderit possimus tenetur adipisci eaque eum.'} </p> </div> <button color="secondary" variant="contained" className="w-full py-4 mx-auto" type="submit" > Add to cart </button> </div> </div> </div> ); }; export default Product; export async function getStaticPaths() { let paths = (); try { const data = await fetchProduct(); const products = data?.products?.items || (); paths = products.map((product) => ({ params: { urlKey: product?.url_key || '404' }, })); } catch (error) { console.error('Error fetching data from API:', error); } return { paths, fallback: 'blocking' }; } export async function getStaticProps({ params }) { const productInfo = await fetchProduct(params?.urlKey); const product = productInfo?.products?.items?.(0) || null; if (product.length > 0) { return { notFound: true, }; } return { props: { product: product, }, revalidate: 100, }; } const fetchProduct = async (urlKey = null) => { const URL = `${process.env.API_URL}api/${process.env.API_VERSION}/product-list`; const filter = {}; if (urlKey) { filter.url_key = { eq: urlKey }; } const response = await fetch(URL, { method: 'POST', headers: { 'Content-Type': 'application/json', Authenticate: `${process.env.CLIENT_TOKEN}`, }, body: JSON.stringify({ filter: filter, }), }); if (response.status !== 200) { throw new Error(`API request failed with status ${response.status}`); } return response.json(); };
And finally, enter the URL ( ) on your browser and you can see the product page like the image below.

for more information you can consult the official documentation Documentation.
Happy coding!!