What You'll Build

A dynamic product catalog powered by Google Sheets. Update your inventory in real-time without touching code. Perfect for small e-commerce stores, marketplaces, and MVPs.

Step 1: Set Up Your Product Sheet

Create a Google Sheet with these columns:

  • Product Name - Name of the product
  • Price - Product price (numeric)
  • Description - Short product description
  • Image URL - Link to product image
  • Category - Product category (Electronics, Clothing, etc.)
  • In Stock - Yes or No

Add a few sample products to test with.

Step 2: Connect Your Sheet

Add your Google Sheet to SheetAPI.pro and get your API credentials. The API will automatically sync with your Sheet in real-time.

Step 3: Build the Frontend

Use the HTML/JavaScript snippet to create a product grid with category filtering. The code fetches products from the API and renders them dynamically.

Step 4: Add Filtering & Search

The provided code includes category filtering. You can extend it with search functionality, price range filters, or sorting options.

Step 5: Style & Deploy

Customize the CSS to match your brand. Deploy to any static hosting platform. Your product data updates automatically when you edit the Sheet!

Use Cases

  • Small e-commerce - Simple product catalog without complex databases
  • Market vendors - Update inventory on-the-go from mobile
  • MVPs - Validate your product idea before building full infrastructure
  • Dropshipping - Sync products from supplier sheets

Advanced Features

  • Add a shopping cart using localStorage
  • Integrate with Stripe or PayPal for payments
  • Set up webhooks to sync with other platforms
  • Add product variants (size, color) with additional columns
  • Track inventory levels and low-stock alerts
HTML
JavaScript
React
Python
PHP
cURL
<!DOCTYPE html>
<html>
<head>
    <title>Product Catalog</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f5f5f5; }
        h1 { text-align: center; }
        .filters { display: flex; gap: 10px; margin-bottom: 20px; justify-content: center; }
        .filters button { padding: 10px 20px; border: none; background: #ddd; cursor: pointer; border-radius: 4px; }
        .filters button.active { background: #667eea; color: white; }
        .products { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 20px; }
        .product { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .product img { width: 100%; height: 200px; object-fit: cover; border-radius: 4px; }
        .product h3 { margin: 10px 0; }
        .product .price { font-size: 1.5rem; color: #667eea; font-weight: bold; }
        .product .stock { color: green; font-size: 0.9rem; }
        .product .out-of-stock { color: red; }
    </style>
</head>
<body>
    <h1>Our Products</h1>
    <div class="filters" id="filters"></div>
    <div class="products" id="products"></div>
    <script src="catalog.js"></script>
</body>
</html>
const API_URL = 'https://sheetapi.pro/api/v1/sheets/YOUR_SHEET_ID/data';
const API_KEY = 'YOUR_API_KEY';

let allProducts = [];
let currentCategory = 'all';

async function loadProducts() {
    try {
        const response = await fetch(API_URL, {
            headers: { 'Authorization': `Bearer ${API_KEY}` }
        });
        
        const data = await response.json();
        allProducts = data.data || [];
        
        renderFilters();
        renderProducts();
    } catch (error) {
        console.error('Failed to load products:', error);
    }
}

function renderFilters() {
    const categories = ['all', ...new Set(allProducts.map(p => p.Category))];
    const filtersDiv = document.getElementById('filters');
    
    filtersDiv.innerHTML = categories.map(cat => 
        `<button class="${cat === currentCategory ? 'active' : ''}" 
                onclick="filterByCategory('${cat}')">${cat}</button>`
    ).join('');
}

function filterByCategory(category) {
    currentCategory = category;
    renderFilters();
    renderProducts();
}

function renderProducts() {
    const filtered = currentCategory === 'all' 
        ? allProducts 
        : allProducts.filter(p => p.Category === currentCategory);
    
    const productsDiv = document.getElementById('products');
    
    productsDiv.innerHTML = filtered.map(product => `
        <div class="product">
            <img src="${product['Image URL']}" alt="${product['Product Name']}">
            <h3>${product['Product Name']}</h3>
            <p>${product.Description}</p>
            <div class="price">$${product.Price}</div>
            <div class="${product['In Stock'] === 'Yes' ? 'stock' : 'out-of-stock'}">
                ${product['In Stock'] === 'Yes' ? '✓ In Stock' : '✗ Out of Stock'}
            </div>
        </div>
    `).join('');
}

loadProducts();
import React, { useState, useEffect } from 'react';

const API_URL = 'https://sheetapi.pro/api/v1/sheets/YOUR_SHEET_ID/data';
const API_KEY = 'YOUR_API_KEY';

function ProductCatalog() {
    const [products, setProducts] = useState([]);
    const [category, setCategory] = useState('all');
    const [loading, setLoading] = useState(true);
    
    useEffect(() => {
        fetch(API_URL, {
            headers: { 'Authorization': `Bearer ${API_KEY}` }
        })
        .then(res => res.json())
        .then(data => {
            setProducts(data.data || []);
            setLoading(false);
        })
        .catch(err => console.error(err));
    }, []);
    
    const categories = ['all', ...new Set(products.map(p => p.Category))];
    const filtered = category === 'all' 
        ? products 
        : products.filter(p => p.Category === category);
    
    if (loading) return <div>Loading...</div>;
    
    return (
        <div>
            <h1>Product Catalog</h1>
            <div className="filters">
                {categories.map(cat => (
                    <button 
                        key={cat}
                        className={cat === category ? 'active' : ''}
                        onClick={() => setCategory(cat)}
                    >
                        {cat}
                    </button>
                ))}
            </div>
            <div className="products">
                {filtered.map((product, i) => (
                    <div key={i} className="product">
                        <img src={product['Image URL']} alt={product['Product Name']} />
                        <h3>{product['Product Name']}</h3>
                        <p>{product.Description}</p>
                        <div className="price">${product.Price}</div>
                        <div className={product['In Stock'] === 'Yes' ? 'stock' : 'out-of-stock'}>
                            {product['In Stock'] === 'Yes' ? '✓ In Stock' : '✗ Out of Stock'}
                        </div>
                    </div>
                ))}
            </div>
        </div>
    );
}

export default ProductCatalog;
import requests
from flask import Flask, jsonify, request

app = Flask(__name__)

SHEET_ID = 'YOUR_SHEET_ID'
API_KEY = 'YOUR_API_KEY'
API_URL = f'https://sheetapi.pro/api/v1/sheets/{SHEET_ID}/data'

@app.route('/api/products', methods=['GET'])
def get_products():
    headers = {'Authorization': f'Bearer {API_KEY}'}
    
    # Get optional category filter
    category = request.args.get('category')
    
    response = requests.get(API_URL, headers=headers)
    
    if response.status_code == 200:
        products = response.json().get('data', [])
        
        # Filter by category if specified
        if category and category != 'all':
            products = [p for p in products if p.get('Category') == category]
        
        return jsonify({
            'success': True,
            'count': len(products),
            'products': products
        })
    else:
        return jsonify({'success': False, 'error': 'Failed to fetch products'}), 500

if __name__ == '__main__':
    app.run(debug=True)
<?php
// products-api.php
header('Content-Type: application/json');

$sheetId = 'YOUR_SHEET_ID';
$apiKey = 'YOUR_API_KEY';
$apiUrl = "https://sheetapi.pro/api/v1/sheets/{$sheetId}/data";

$category = $_GET['category'] ?? 'all';

$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer {$apiKey}"
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode === 200) {
    $data = json_decode($response, true);
    $products = $data['data'] ?? [];
    
    // Filter by category
    if ($category !== 'all') {
        $products = array_filter($products, function($p) use ($category) {
            return $p['Category'] === $category;
        });
        $products = array_values($products); // Re-index
    }
    
    echo json_encode([
        'success' => true,
        'count' => count($products),
        'products' => $products
    ]);
} else {
    http_response_code(500);
    echo json_encode(['success' => false, 'error' => 'Failed to fetch']);
}
?>
# Get all products
curl -X GET https://sheetapi.pro/api/v1/sheets/YOUR_SHEET_ID/data \
  -H "Authorization: Bearer YOUR_API_KEY"

# Add a new product
curl -X POST https://sheetapi.pro/api/v1/sheets/YOUR_SHEET_ID/data \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "Product Name": "Wireless Headphones",
    "Price": "89.99",
    "Description": "Premium noise-canceling headphones",
    "Image URL": "https://example.com/headphones.jpg",
    "Category": "Electronics",
    "In Stock": "Yes"
  }'