I'm using snipcart in a nextjs with strapi app. I receive an error when processing a payment :
A 'cart-confirmation' error occured in Snipcart. Reason:
'product-crawling-failed' [Details] We have not been able to find item with id '59' at 'https://cmeditions.fr/products/selfless'. Please make sure the product is correctly defined.
and :
An attempt to create an order with invalid products has been made. Don't forget you can't add/update items attributes in the cart dynamically with javascript as it will cause crawling issues
It works when data-item-id is replaced by a static value but not with somthing like {product.id}
Here is my component [sulg].js :
const ProductPage = ({ product }) => {
const router = useRouter()
if (router.isFallback) {
return <div>Loading product...</div>
}
return (
<div className="carousel-container m-6 grid grid-cols-1 gap-4 mt-8 items-start">
<Head>
<title>{product.title}</title>
</Head>
<div className="rounded-t-lg pt-2 pb-2 m-auto h-auto">
<EmblaCarousel {...product} />
</div>
<div className="w-full p-5 flex flex-col justify-between">
<div>
<h4 className="mt-1 font-semibold leading-tight truncate text-slate">
<span className="uppercase text-lg font-bold">{product.title}</span>
<br />
{product.author}
</h4>
<LanguageDesc {...product} />
</div>
<div className="flex flex-col md:flex-row">
<div className="mt-4 font-semibold leading-tight truncate text-slate">
<p>{product.year}</p>
<p>Format: {product.size}</p>
<p>Printing: {product.technic}</p>
<p>Paper: {product.medium}</p>
<p>{product.page}</p>
<p>{product.copies} copies</p>
<p>{product.price}€</p>
</div>
{product.status === "published" ? (
<button
className="snipcart-add-item mt-4 ml-16 self-center bg-slate border border-gray-200 d hover:shadow-lg hover:bg-brique focus:outline-none text-white font-semibold leading-none py-2 px-4 w-20 h-20 rounded-full"
data-item-id={product.id}
data-item-price={product.price}
data-item-url={router.asPath}
data-item-description={product.description}
data-item-image={getStrapiMedia(
product.image.formats.thumbnail.url
)}
data-item-name={product.title}
v-bind="customFields"
>
Add to cart
</button>
) : (
<div className="text-center mr-10 mb-1" v-else>
<div
className="p-2 bg-indigo-800 items-center text-indigo-100 leading-none lg:rounded-full flex lg:inline-flex"
role="alert"
>
<span className="flex rounded-full bg-indigo-500 uppercase px-2 py-1 text-xs font-bold mr-3">
Coming soon...
</span>
<span className="font-semibold mr-2 text-left flex-auto">
This article is not available yet.
</span>
</div>
</div>
)}
</div>
</div>
</div>
)
}
export async function getStaticProps({ params }) {
const product = await getProduct(params.slug)
return { props: { product } }
}
export async function getStaticPaths() {
const products = await getProducts()
return {
paths: products.map((_product) => {
return {
params: { slug: _product.slug },
}
}),
fallback: true,
}
}
export default ProductPage
EDIT
I tried to return a json to the validator, but I think it isn't right
/api/products.js
import { getProducts } from "../../utils/api"
// eslint-disable-next-line import/no-anonymous-default-export
export default async function (_req, res) {
return new Promise((resolve) => {
getProducts()
.then((response) => {
res.statusCode = 200
res.setHeader("Content-Type", "application/json")
res.setHeader("Cache-Control", "max-age=180000")
res.end(JSON.stringify(response))
resolve()
})
.catch((error) => {
res.json(error)
res.status(405).end()
resolve() // in case something goes wrong in the catch block (as vijay commented)
})
})
}
api.js
export function getStrapiURL(path) {
return `${
process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
}${path}`
}
// Helper to make GET requests to Strapi
export async function fetchAPI(path) {
const requestUrl = getStrapiURL(path)
const response = await fetch(requestUrl)
const data = await response.json()
return data
}
export async function getCategories() {
const categories = await fetchAPI("/categories")
return categories
}
export async function getCategory(slug) {
const categories = await fetchAPI(`/categories?slug=${slug}`)
return categories?.[0]
}
export async function getProducts() {
const products = await fetchAPI("/products")
return products
}
export async function getProduct(slug) {
const products = await fetchAPI(`/products?slug=${slug}`)
return products?.[0]
}
export async function getLibrairies() {
const librairies = await fetchAPI("/librairies")
return librairies
}
export async function getLibrairie(slug) {
const librairies = await fetchAPI(`/librairies?slug=${slug}`)
return librairies?.[0]
}
It finally wasn't a matter of JSON crawler but something to see with the domain on the snipcart dashboard. I had to put the vercel.app domain first and my own domain name as a subdomain. It worked when I changed this. This is the only explaination I got