Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate Ecwid with V0

To use Ecwid with V0, embed the Ecwid store widget in your Next.js page, or create a Next.js API route at app/api/ecwid/route.ts that fetches store products and categories via Ecwid's REST API using your Store ID and secret key from Vercel environment variables. Ecwid's embeddable widget is the fastest integration — the REST API lets you build fully custom storefronts.

What you'll learn

  • How to embed the Ecwid store widget in a V0-generated Next.js page
  • How to create a Next.js API route that fetches Ecwid products and categories
  • How to store Ecwid credentials securely in Vercel environment variables
  • How to build a custom product listing page using Ecwid's REST API data
  • How to handle Ecwid API pagination for stores with large product catalogs
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read20 minutesE-commerceApril 2026RapidDev Engineering Team
TL;DR

To use Ecwid with V0, embed the Ecwid store widget in your Next.js page, or create a Next.js API route at app/api/ecwid/route.ts that fetches store products and categories via Ecwid's REST API using your Store ID and secret key from Vercel environment variables. Ecwid's embeddable widget is the fastest integration — the REST API lets you build fully custom storefronts.

Adding an Ecwid Store to Your V0-Built Website

Ecwid is one of the most popular embeddable e-commerce solutions, used by over 130,000 merchants who want to add a store to an existing website without rebuilding it on a dedicated e-commerce platform. Its core strength is that you can embed a complete, functional online store into any web page with a simple script tag. For V0 builders, this means you can generate a beautiful marketing site or product page with V0 and layer on real e-commerce functionality through Ecwid without building checkout, cart, or payment flows from scratch.

Ecwid offers two integration approaches that serve different needs. The widget embed is the quickest path: Ecwid provides a JavaScript snippet that renders the full store interface inside a div on your page. It handles product listings, filtering, cart functionality, checkout, and payment processing entirely within the widget. This requires virtually no code — just a client component that loads the script. The REST API approach gives you full control: fetch product data and categories programmatically, display them in your own V0-generated UI components, and handle navigation and filtering with Next.js routing. The REST API is better for custom-designed storefronts where you want pixel-perfect control over the layout.

Ecwid's REST API uses a Store ID (public) and Secret Token (private) for authentication. The Store ID is safe to include in client-side code because it is embedded in Ecwid's widget script URL. The Secret Token, however, provides full read-write API access and must stay server-side. All product reads via the REST API are public if your store's catalog is set to public visibility, but for any writes (creating orders, updating inventory) or accessing private data, the Secret Token is required.

Integration method

Next.js API Route

V0 generates your storefront UI components while a Next.js API route fetches product and category data from Ecwid's REST API server-side using your secret key. Alternatively, Ecwid's JavaScript widget can be embedded directly in a client component for a plug-and-play store experience without custom API routes.

Prerequisites

  • A V0 account at v0.dev with a Next.js project
  • An Ecwid account at ecwid.com (free plan available for up to 10 products)
  • Your Ecwid Store ID from Ecwid Control Panel → Settings → General → Store Profile
  • An Ecwid Secret Token from Ecwid Control Panel → Apps → Legacy API Keys for REST API access
  • A Vercel account with your V0 project deployed via GitHub

Step-by-step guide

1

Generate the Storefront UI in V0

Start by prompting V0 to build the page layout and UI components for your Ecwid store integration. The approach differs based on whether you are using the widget embed or the REST API approach. For the widget embed path: prompt V0 to generate the page layout with a specific placeholder container element. Give the container a clear ID (like 'ecwid-store' or 'my-store-widget') because the Ecwid widget script targets this element ID. Include a loading state in the placeholder since the widget takes 1-2 seconds to initialize. The surrounding layout — header, navigation, footer, and any marketing content above the store — should all be generated by V0. For the REST API path: prompt V0 to generate product card components, category navigation, filter panels, and the product grid layout. Tell V0 explicitly what data shape to expect from your API route so it generates the correct TypeScript interfaces and renders the data fields correctly. Ecwid's product objects have: id, name, price, thumbnailUrl, url, description, inStock, and category data. Providing this structure in your V0 prompt results in cleaner generated code. A common V0 limitation with e-commerce UIs is the 'Add to Cart' button behavior. V0 will generate the button and perhaps a cart icon in the header, but connecting the cart state across components requires either React context, a state management solution, or Ecwid's built-in cart handling. If you are using the Ecwid widget, the cart is managed entirely by Ecwid. If you are building a custom storefront with the REST API, cart management is a significant additional implementation task that V0 will scaffold but not fully wire together. Plan for this gap when estimating integration complexity.

V0 Prompt

Create an e-commerce storefront page. Include: a top navigation with logo placeholder, 'Shop', 'About', and 'Contact' links, and a cart icon with item count badge on the right. Below: a hero banner with 'Free shipping on orders over $75' text. Then a product grid section with heading 'All Products', a horizontal category filter pills row (All / Clothing / Accessories / Home Goods), and a 3-column grid of product cards. Each card: rectangular image placeholder (aspect ratio 3:4), product name, category label in small gray text, price in black bold, and 'Add to Cart' button. Connect the cards to GET /api/ecwid/products.

Paste this in V0 chat

Pro tip: Ask V0 to create skeleton loading placeholders for the product cards so users see the layout structure immediately while the API route fetches Ecwid data.

Expected result: V0 generates a professional e-commerce product listing page with category filters, product grid, and Add to Cart buttons wired to your Ecwid API route.

2

Create the Ecwid REST API Route

Create the Next.js API route that fetches product data from Ecwid's REST API. Ecwid's REST API endpoint for products is https://app.ecwid.com/api/v3/{storeId}/products. Authentication uses the Secret Token as a Bearer token in the Authorization header. Ecwid's product listing endpoint supports a rich set of query parameters: offset and limit for pagination (default 100 products per page, maximum 100), sortBy for ordering (ADDED_TIME_DESC, PRICE_ASC, PRICE_DESC, etc.), keyword for search, and categoryId to filter by category. Pass these through from your API route's query parameters so the V0-generated frontend can control filtering and pagination. For a 'top integration for ecwid' query focus — the most valuable capability to expose is the category-aware product listing combined with pagination. Ecwid stores can have hundreds of products, and fetching all of them at once is both slow and expensive in terms of API quota. Implement offset-based pagination in your API route: accept offset and limit parameters from the client and pass them to Ecwid's API. Ecwid's product objects include an isShippingRequired field, a weight field, and variations (product options like sizes and colors) as nested arrays. For simple product listing pages, you only need the core fields. For product detail pages, fetch a single product by ID using GET https://app.ecwid.com/api/v3/{storeId}/products/{productId} which returns the full product object including description HTML, gallery images array, and all option combinations. Note that Ecwid's REST API returns product prices in the store's default currency. For international stores, the currency symbol and formatting are in the store profile endpoint (GET /api/v3/{storeId}/profile). Fetch this once on page load and cache it for the duration of the session.

V0 Prompt

Create a Next.js API route at app/api/ecwid/products/route.ts. Accept GET requests with optional query parameters: categoryId, offset (default 0), limit (default 20), sortBy. Fetch products from Ecwid REST API v3 using ECWID_STORE_ID and ECWID_SECRET_TOKEN from environment variables. Return an array of products with id, name, price, thumbnailUrl, inStock, and url fields, plus total count for pagination.

Paste this in V0 chat

app/api/ecwid/products/route.ts
1import { NextRequest, NextResponse } from 'next/server';
2
3const ECWID_STORE_ID = process.env.ECWID_STORE_ID!;
4const ECWID_SECRET_TOKEN = process.env.ECWID_SECRET_TOKEN!;
5const ECWID_BASE = `https://app.ecwid.com/api/v3/${ECWID_STORE_ID}`;
6
7export async function GET(request: NextRequest) {
8 try {
9 const { searchParams } = new URL(request.url);
10 const categoryId = searchParams.get('categoryId');
11 const offset = searchParams.get('offset') || '0';
12 const limit = searchParams.get('limit') || '20';
13 const sortBy = searchParams.get('sortBy') || 'ADDED_TIME_DESC';
14
15 const params = new URLSearchParams({
16 offset,
17 limit,
18 sortBy,
19 ...(categoryId && { categoryId }),
20 });
21
22 const response = await fetch(
23 `${ECWID_BASE}/products?${params}`,
24 {
25 headers: {
26 Authorization: `Bearer ${ECWID_SECRET_TOKEN}`,
27 'Content-Type': 'application/json',
28 },
29 next: { revalidate: 60 }, // Cache for 60 seconds
30 }
31 );
32
33 if (!response.ok) {
34 return NextResponse.json(
35 { error: `Ecwid API error: ${response.status}` },
36 { status: response.status }
37 );
38 }
39
40 const data = await response.json();
41
42 // Shape the response to only what the UI needs
43 const products = data.items?.map((p: Record<string, unknown>) => ({
44 id: p.id,
45 name: p.name,
46 price: p.price,
47 compareToPrice: p.compareToPrice,
48 thumbnailUrl: p.thumbnailUrl,
49 url: p.url,
50 inStock: p.inStock,
51 description: p.description,
52 })) || [];
53
54 return NextResponse.json({
55 products,
56 total: data.total,
57 offset: data.offset,
58 limit: data.limit,
59 });
60 } catch (error) {
61 console.error('Ecwid products error:', error);
62 return NextResponse.json(
63 { error: 'Failed to fetch products' },
64 { status: 500 }
65 );
66 }
67}

Pro tip: Use Next.js fetch caching (next: { revalidate: 60 }) for product listing calls to avoid hitting Ecwid's API on every page view. Product data changes infrequently enough that a 60-second cache is usually acceptable.

Expected result: The API route returns paginated product data from your Ecwid store. The V0-generated product grid renders real product names, prices, and thumbnail images.

3

Add Ecwid Credentials to Vercel Environment Variables

Your API route needs two Ecwid credentials: the Store ID and the Secret Token. Add these to Vercel's environment configuration. Go to Vercel Dashboard → your project → Settings → Environment Variables and add: ECWID_STORE_ID: Your numeric Ecwid store ID. Find it in Ecwid Control Panel → Settings → General → Store Profile. It is also visible in your browser's URL when viewing your control panel, and in the widget JavaScript snippet Ecwid provides. This is technically a public identifier (it appears in widget script URLs), but there is no benefit to exposing it client-side, so keep it server-side. ECWID_SECRET_TOKEN: The legacy API key / secret token from Ecwid Control Panel → Apps → Legacy API Keys → Generate Tokens. This provides full API access including write operations. Do NOT add NEXT_PUBLIC_ prefix. Store it as a server-only environment variable. For the widget embed approach, you will also want NEXT_PUBLIC_ECWID_STORE_ID with the same Store ID value. The Ecwid widget script URL includes the Store ID directly: https://app.ecwid.com/script.js?{storeId}. Since this is a public URL pattern and the Store ID appears in your page HTML anyway, NEXT_PUBLIC_ is appropriate here for the widget approach only. After saving all variables, trigger a new Vercel deployment. Check the Vercel function logs (Vercel Dashboard → Functions → View Function Logs) after making a request to /api/ecwid/products to confirm the API route is fetching data successfully.

.env.local
1# .env.local local development
2ECWID_STORE_ID=12345678
3ECWID_SECRET_TOKEN=your_secret_token_here
4# For widget embed (client-side use is safe for Store ID only)
5NEXT_PUBLIC_ECWID_STORE_ID=12345678

Pro tip: Ecwid secret tokens do not expire automatically, but you should regenerate and update them if you suspect exposure. Legacy API keys with narrower scope (public_token for read-only) are available if you only need to fetch product data.

Expected result: ECWID_STORE_ID and ECWID_SECRET_TOKEN are saved in Vercel. After redeployment, the API route returns product data without authentication errors.

4

Add the Ecwid Widget Embed (Alternative to API Route)

If you prefer the plug-and-play widget approach over building a custom storefront, embed Ecwid's JavaScript widget in your Next.js page. The widget loads Ecwid's full store interface including product listings, cart, and checkout directly in your page with no API routes needed. Create a client component that loads the Ecwid script and initializes the store widget on a specific container element. The Ecwid widget requires a global JavaScript snippet and a div with a specific ID that it will render into. In Next.js App Router, this must be a client component with 'use client' because it manipulates the DOM after mount. Ecwid's standard embed consists of two parts: a configuration object (window.ec.config) that sets the store ID and widget mode, and the JavaScript snippet that loads the Ecwid storefront assets. The configuration must be set before the script loads. For Next.js App Router, use a useEffect where you set the config and then append the script tag. The Ecwid widget renders the full Ecwid storefront at the container element, including navigation, category pages, product pages, cart, and checkout. It handles its own internal routing using hash-based navigation by default. This means users navigating within the store do not cause full Next.js route changes — the Next.js router is not involved in Ecwid's internal product and category pages. A V0-specific caveat: V0 may generate the Ecwid widget as a server component using next/script, which will not work correctly for the initialization pattern. Ensure the component is a client component with 'use client'. Also, if V0 generates the widget script loading in a way that conflicts with React's rendering lifecycle (for example, appending the script in the render function instead of useEffect), the store may initialize multiple times or fail to render.

V0 Prompt

Create an EcwidStore client component at components/ecwid-store.tsx. Use 'use client' and useEffect. In the effect: set window.ec = window.ec || {}; window.ec.storefront = window.ec.storefront || {}; then create a script tag with src 'https://app.ecwid.com/script.js?{NEXT_PUBLIC_ECWID_STORE_ID}' and append it to document.body. Return a div with id='my-store-123456' and className 'w-full min-h-[600px]'. Replace 123456 with the actual store ID from environment variables.

Paste this in V0 chat

components/ecwid-store.tsx
1'use client';
2
3import { useEffect } from 'react';
4
5declare global {
6 interface Window {
7 ec?: {
8 config?: Record<string, unknown>;
9 storefront?: Record<string, unknown>;
10 };
11 ecwid_script_defer?: boolean;
12 ecwid_dynamic_widgets?: boolean;
13 }
14}
15
16export function EcwidStore() {
17 const storeId = process.env.NEXT_PUBLIC_ECWID_STORE_ID;
18
19 useEffect(() => {
20 if (!storeId) {
21 console.warn('EcwidStore: NEXT_PUBLIC_ECWID_STORE_ID is not set');
22 return;
23 }
24
25 const scriptId = `ecwid-script-${storeId}`;
26 if (document.getElementById(scriptId)) return;
27
28 // Configure Ecwid
29 window.ec = window.ec || {};
30 window.ec.config = window.ec.config || {};
31 window.ecwid_script_defer = true;
32 window.ecwid_dynamic_widgets = true;
33
34 const script = document.createElement('script');
35 script.id = scriptId;
36 script.src = `https://app.ecwid.com/script.js?${storeId}`;
37 script.async = true;
38 document.body.appendChild(script);
39 }, [storeId]);
40
41 return (
42 <div
43 id={`my-store-${storeId}`}
44 className="w-full min-h-[600px]"
45 />
46 );
47}

Pro tip: The Ecwid widget container div ID must match the format 'my-store-{storeId}' exactly — Ecwid's script looks for this specific pattern to find the container element.

Expected result: The Ecwid store widget renders inside your Next.js page, showing your actual Ecwid product catalog with full shopping cart and checkout functionality.

Common use cases

Embedded Store Widget on a Marketing Site

A small business owner wants to sell physical products directly from their V0-built brand website. V0 generates the hero section, about page, and blog — and an Ecwid widget is embedded on the /shop page, providing full e-commerce functionality including cart, checkout, and payment without any custom API code.

V0 Prompt

Create a /shop page for a handmade ceramics store. Include: a page header with 'Our Collection' heading and subtitle 'Each piece is handcrafted in small batches', a short introductory paragraph about the craft process, then a full-width section with id='ecwid-store' and minimum height of 600px with a light gray background and loading text 'Loading store...'. Add a client script loader for the Ecwid widget below the fold.

Copy this prompt to try it in V0

Custom Product Grid with Ecwid Data

A fashion brand wants a custom-designed product listing page that matches their visual identity precisely. V0 generates the product card components, filters, and grid layout. A Next.js API route fetches the product data from Ecwid's REST API, and the V0-generated components render it with custom styling.

V0 Prompt

Create a product listing page with a filter sidebar and a product grid. Filter sidebar: category checkboxes, price range slider from $0-$500, and a Sort dropdown (Newest First / Price Low to High / Price High to Low). Product grid: 3-column desktop, 2-column tablet, 1-column mobile. Each product card: square image placeholder, product name, price in bold, a star rating (4.5 stars shown as filled/half/empty icons), and an 'Add to Cart' button. Fetch products from GET /api/ecwid/products with filter and sort query parameters.

Copy this prompt to try it in V0

Product Detail Page with Related Products

A seller wants individual product pages with full descriptions, multiple image galleries, and related product recommendations. V0 generates the product detail page layout. The API route fetches the specific product by ID and a set of related products from the same category using Ecwid's REST API.

V0 Prompt

Create a product detail page. Left side: an image gallery with a large main image and 4 thumbnail images below. Right side: product name as h1, price in large font, a color variant selector (swatches), a quantity input with +/- buttons, an 'Add to Cart' button (full width, dark), and a 'Buy Now' button. Below the fold: a tabbed section with Description and Shipping Policy tabs. After those tabs: a 'You might also like' section with 4 product cards. Fetch the product from GET /api/ecwid/products/[id].

Copy this prompt to try it in V0

Troubleshooting

Ecwid widget container shows but no products appear — widget stays blank

Cause: Either the NEXT_PUBLIC_ECWID_STORE_ID environment variable is missing, the container div ID does not match the expected 'my-store-{storeId}' pattern, or the script initialization ran before the container div was added to the DOM.

Solution: Check the browser console for Ecwid-related errors. Verify that NEXT_PUBLIC_ECWID_STORE_ID is set in Vercel environment variables and that the container div ID is exactly 'my-store-' followed by your numeric Store ID (e.g., 'my-store-12345678'). Ensure the component using useEffect is a client component with 'use client'.

API route returns 403 Forbidden from Ecwid

Cause: The ECWID_SECRET_TOKEN is invalid, expired, or does not have the required permissions for the endpoint being called.

Solution: Regenerate the secret token in Ecwid Control Panel → Apps → Legacy API Keys. Update ECWID_SECRET_TOKEN in Vercel environment variables and redeploy. Verify the token starts with the correct prefix for your token type.

Products fetch correctly in development but return empty array in production

Cause: ECWID_STORE_ID or ECWID_SECRET_TOKEN is missing from Vercel's Production environment scope (might be set only for Development or Preview).

Solution: In Vercel Dashboard → Settings → Environment Variables, click on each variable and verify it is enabled for the Production environment. Environment variables can be scoped to specific environments. After updating, redeploy the project.

V0-generated component causes hydration error with Ecwid widget

Cause: The Ecwid widget manipulates the DOM directly after mounting, causing a mismatch between the server-rendered HTML and the client-rendered HTML.

Solution: Wrap the EcwidStore component with Next.js dynamic import with ssr: false. This ensures the Ecwid widget only renders client-side and avoids the server/client HTML mismatch that causes hydration errors.

typescript
1// In the parent page component
2import dynamic from 'next/dynamic';
3
4const EcwidStore = dynamic(
5 () => import('../components/ecwid-store').then((mod) => mod.EcwidStore),
6 { ssr: false }
7);

Best practices

  • Store ECWID_SECRET_TOKEN as a server-side environment variable without NEXT_PUBLIC_ prefix — it provides full read-write API access and must never be exposed in the browser.
  • Use Next.js fetch caching (next: { revalidate: 60 }) for product listing API calls to reduce Ecwid API usage for high-traffic stores.
  • For the widget embed, wrap the component in dynamic(() => import(...), { ssr: false }) to prevent hydration mismatches caused by Ecwid's DOM manipulation.
  • Use Ecwid's public_token (read-only) for product listing endpoints instead of the secret token if you only need to display products, reducing the risk of credential exposure.
  • Implement pagination in your product API route from the start — Ecwid stores can grow to thousands of products, and fetching all at once will be slow.
  • Shape the API response to only include fields the UI needs — Ecwid product objects are large, and trimming them reduces response payload size.
  • Add a fallback UI in the widget container while the Ecwid script loads to prevent the appearance of blank content above the fold.
  • Test with your actual Ecwid store products before deploying — the widget's appearance depends on your store's categories, images, and product data.

Alternatives

Frequently asked questions

What is the difference between Ecwid's widget embed and using its REST API?

The widget embed requires pasting a script tag into your page and provides a complete, styled store interface managed entirely by Ecwid. The REST API lets you fetch product data and build a fully custom storefront with your own components. The widget takes 5 minutes to implement; the REST API storefront takes several hours to build properly. Use the widget for quick store additions, and the REST API when you need full design control.

Can V0 automatically generate an Ecwid integration?

V0 can generate the UI components and API route boilerplate when you describe the Ecwid integration specifically. For the widget embed, provide V0 with the exact initialization pattern (the window.ec config and script loading). For the REST API, tell V0 the product data schema so it generates correct TypeScript interfaces. Always verify V0's generated code against Ecwid's current API documentation.

Does Ecwid's free plan support API access?

Ecwid's free plan (Venture, limited to 10 products) provides access to the REST API. However, some advanced API features like product variations and discount codes require paid plans. The widget embed is available on all plans including free. Check Ecwid's pricing page for the full API feature comparison across plans.

How do I handle Ecwid cart events in my custom V0 UI?

Ecwid provides a JavaScript event system (window.Ecwid.OnCartChanged callback) that fires when the cart is updated. In a custom storefront using the REST API, you would build your own cart state management. If you are using the Ecwid widget, Ecwid manages the cart internally and fires events you can listen to. For full custom cart UI, the REST API includes order creation endpoints that let you programmatically manage cart and checkout flows.

Can I use Ecwid with a custom domain and V0-deployed site?

Yes. Ecwid operates independently of your domain — you can deploy your V0 app to any Vercel domain and embed the Ecwid widget or use the REST API. For custom domains, ensure your Vercel deployment is on your custom domain before setting up any OAuth callbacks. The Ecwid store URL in your Ecwid Control Panel is separate from your V0 app's URL.

Does the Ecwid widget slow down page loading?

The Ecwid widget JavaScript file is several hundred kilobytes and loaded asynchronously. It does not block the initial page render, but it does add to the overall page weight. For performance, set ecwid_script_defer = true to defer loading and use dynamic import with ssr: false to prevent the widget from affecting your server-rendered page's Time to First Byte metric.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.