Socket
Book a DemoInstallSign in
Socket

@multidots/sanity-plugin-amazon-product-sync

Package Overview
Dependencies
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@multidots/sanity-plugin-amazon-product-sync

Sanity Studio plugin to fetch and embed Amazon products by ASIN (PA-API v5), with settings tool and document actions.

1.0.8
latest
npmnpm
Version published
Weekly downloads
198
-62.21%
Maintainers
1
Weekly downloads
Β 
Created
Source

Sanity Plugin: Amazon Product Sync

A comprehensive Sanity Studio plugin for fetching and managing Amazon products using the Amazon Product Advertising API (PA-API v5). This plugin provides seamless integration between Sanity Studio and Amazon's product data with real-time fetching capabilities.

πŸš€ Features

  • Amazon Settings Management: Configure PA-API credentials with a dedicated settings singleton
  • Real-time Form Validation: Instant feedback and button state updates using useFormValue
  • Product Document Management: Create multiple Amazon product documents with auto-fetching
  • Fetch from Amazon Button: Dedicated button component for product data retrieval
  • Multi-region Support: US, UK, DE, FR, IT, ES, CA, AU, JP, IN marketplaces
  • Streamlined Product Data: Essential fields including title, brand, pricing, images, and more
  • TypeScript Support: Full type safety throughout the plugin
  • Modern Sanity v4: Built for the latest Sanity Studio architecture
  • Secure Configuration: Environment variable-based API endpoint configuration

Amazon Product Sync plugin overview in Sanity Studio

API Settings: https://share.cleanshot.com/sYc88tRMBvHPvsjvt9YT

Product Fields Display Settings: https://share.cleanshot.com/Nrtl8RpdhgJrSr7Lj0j6

Test Connection and Debug Actions: https://share.cleanshot.com/Nrtl8RpdhgJrSr7Lj0j6

πŸ“¦ Installation

npm install @multidots/sanity-plugin-amazon-product-sync

βš™οΈ Setup

1. Add Plugin to Sanity Config

// sanity.config.ts
import { defineConfig } from 'sanity'
import { structureTool } from 'sanity/structure'
import { visionTool } from '@sanity/vision'
import { amazonProductsPlugin } from '@multidots/sanity-plugin-amazon-product-sync'
import { structure } from './structure'

export default defineConfig({
  name: 'default',
  title: 'Your Studio',
  projectId: 'your-project-id',
  dataset: 'production',
  
  plugins: [
    structureTool({ structure }),
    visionTool(),
    amazonProductsPlugin(),
  ],
  
  schema: {
    types: [
      // Your existing schemas
    ],
  },
})

2. Create Structure Configuration

Create structure.ts in your project root:

// structure.ts
import type { StructureResolver } from 'sanity/structure'

export const structure: StructureResolver = (S) =>
  S.list()
    .title('Content')
    .items([
      ...S.documentTypeListItems().filter(
        (item) => item.getId() &&
          !['amazon.settings'].includes(item.getId()!)
      ),
      S.divider(),
      S.listItem()
        .id('amazonSettings')
        .title('Amazon Settings')
        .child(
            S.document()
                .schemaType('amazon.settings')
                .documentId('amazon-settings')
        ),
    ])

3. Update Sanity Config for Document Rules

// sanity.config.ts (add these document rules)
export default defineConfig({
  // ... other config
  document: {
    // Hide singleton types from the global "New document" menu
    newDocumentOptions: (prev: any, { creationContext }: any) => {
      if (creationContext.type === 'global') {
        return prev.filter(
          (templateItem: any) =>
            !['amazon.settings'].includes(templateItem.templateId)
        )
      }
      return prev
    },
    // Prevent duplicate/delete on singleton documents
    actions: (prev: any, { schemaType }: any) => {
      if (['amazon.settings'].includes(schemaType)) {
        return prev.filter(({ action }: any) => action !== 'duplicate' && action !== 'delete')
      }
      return prev
    },
  },
  // ... rest of config
})

🌐 Frontend Integration

The plugin requires server-side API routes to handle Amazon PA-API calls due to CORS restrictions and security requirements.

Environment Variables

CRITICAL: You must set up these environment variables in your Sanity Studio root .env.local file:

# .env.local (in Sanity Studio root)
SANITY_STUDIO_AMAZON_API_URL=http://localhost:3001
SANITY_STUDIO_AMAZON_TEST_CONNECTION_PATH=/api/amazon/test-connection
SANITY_STUDIO_AMAZON_FETCH_PRODUCT_PATH=/api/amazon/fetch-product

Important Notes:

  • These environment variables are MANDATORY - the plugin will throw errors if they're missing
  • The API server URL should point to your Next.js/Express server that handles Amazon API calls
  • The paths should match your server-side API route endpoints
  • Environment variables must be prefixed with SANITY_STUDIO_ to be accessible in Sanity Studio
  • NEW: The plugin now validates environment variables at startup and provides clear error messages

Configuration System

The plugin now includes a centralized configuration system (src/lib/config.ts) that:

  • Validates environment variables at startup
  • Provides clear error messages for missing or invalid configurations
  • Ensures secure endpoint configuration without hardcoded URLs
  • Supports flexible API server setups for different environments

Required API Routes

You need to implement these endpoints in your frontend:

  • POST /api/amazon/test-connection - Test PA-API credentials
  • POST /api/amazon/fetch-product - Fetch product data by ASIN

Quick Setup with Next.js

1. Install Dependencies

npm install @sanity/client

2. Environment Variables

Create .env.local:

# Sanity Configuration
NEXT_PUBLIC_SANITY_PROJECT_ID=your-project-id
NEXT_PUBLIC_SANITY_DATASET=production
SANITY_API_TOKEN=your-sanity-api-token

# API Configuration
NEXT_PUBLIC_API_URL=http://localhost:3001

3. Create Sanity Client

// lib/sanity.ts
import { createClient } from '@sanity/client'

export const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || 'production',
  apiVersion: '2025-01-01',
  useCdn: false,
  token: process.env.SANITY_API_TOKEN,
})

export async function getAmazonSettings() {
  const query = `*[_type == "amazon.settings"][0]{
    accessKey,
    secretKey,
    region,
    partnerTag
  }`
  
  return await client.fetch(query)
}

πŸ“Ž Referencing Amazon Products in Your Schemas

You can easily reference Amazon products in your own document schemas using a simple field definition. This allows you to associate Amazon products with blog posts, reviews, comparisons, or any other content type.

Quick Copy-Paste Field

// Copy this field into any schema where you want to reference Amazon products
defineField({
  name: 'amazonProduct',
  title: 'Choose Product',
  type: 'reference',
  to: [{ type: 'amazon.product' }],
  options: {
    filter: ({ document }) => ({
      filter: '_type == "amazon.product"',
      params: {}
    })
  },
  description: 'Select an Amazon product',
})

Field Variations

Single Product (Required):

defineField({
  name: 'amazonProduct',
  title: 'Choose Product',
  type: 'reference',
  to: [{ type: 'amazon.product' }],
  validation: Rule => Rule.required(),
})

Single Product (Optional):

defineField({
  name: 'amazonProduct',
  title: 'Choose Product',
  type: 'reference',
  to: [{ type: 'amazon.product' }],
})

Multiple Products (Array):

defineField({
  name: 'amazonProducts',
  title: 'Choose Products',
  type: 'array',
  of: [
    {
      type: 'reference',
      to: [{ type: 'amazon.product' }],
    }
  ],
  validation: Rule => Rule.min(1).max(10),
})

Example Usage in Schemas

Blog Post with Amazon Product:

export const blogPostSchema = defineType({
  name: 'post',
  title: 'Blog Post',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Title',
      type: 'string',
      validation: Rule => Rule.required(),
    }),
    // Amazon Product Reference
    defineField({
      name: 'amazonProduct',
      title: 'Choose Product',
      type: 'reference',
      to: [{ type: 'amazon.product' }],
      description: 'Select an Amazon product to feature in this blog post',
    }),
    // ... other fields
  ],
})

Product Review Schema:

export const productReviewSchema = defineType({
  name: 'review',
  title: 'Product Review',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Review Title',
      type: 'string',
      validation: Rule => Rule.required(),
    }),
    // Amazon Product Reference (Required)
    defineField({
      name: 'amazonProduct',
      title: 'Choose Product',
      type: 'reference',
      to: [{ type: 'amazon.product' }],
      validation: Rule => Rule.required(),
      description: 'Select the Amazon product being reviewed',
    }),
    defineField({
      name: 'rating',
      title: 'Rating',
      type: 'number',
      options: { range: { min: 1, max: 5, step: 0.5 } },
    }),
    // ... other fields
  ],
})

Product Comparison Schema:

export const comparisonSchema = defineType({
  name: 'comparison',
  title: 'Product Comparison',
  type: 'document',
  fields: [
    defineField({
      name: 'title',
      title: 'Comparison Title',
      type: 'string',
      validation: Rule => Rule.required(),
    }),
    // Multiple Amazon Products
    defineField({
      name: 'amazonProducts',
      title: 'Choose Products',
      type: 'array',
      of: [
        {
          type: 'reference',
          to: [{ type: 'amazon.product' }],
        }
      ],
      validation: Rule => Rule.required().min(2).max(5),
      description: 'Select 2-5 Amazon products to compare',
    }),
    // ... other fields
  ],
})

Frontend Usage with GROQ Queries

Once you have Amazon product references in your schemas, you can query them using GROQ. Here are comprehensive examples:

Basic Single Product Reference

// Get blog post with Amazon product reference
const query = `*[_type == "post" && defined(amazonProduct)][0]{
  _id,
  title,
  slug,
  amazonProduct->{
    _id,
    asin,
    title,
    brand,
    price,
    currency,
    url,
    images,
    features,
    lastSyncedAt
  }
}`

const post = await sanityClient.fetch(query)
console.log(post.amazonProduct.title) // Amazon product title
console.log(post.amazonProduct.price) // Amazon product price

Direct Product Queries

Get product by ASIN:

const query = `*[_type == "amazon.product" && asin == $asin][0]{
  _id, asin, title, brand, price, currency, url, images, features, lastSyncedAt
}`

const product = await sanityClient.fetch(query, { asin: "B09XFQL45V" })

Get product by Reference ID:

const query = `*[_type == "amazon.product" && _id == $referenceId][0]{
  _id, asin, title, brand, price, currency, url, images, features, lastSyncedAt
}`

const product = await sanityClient.fetch(query, { referenceId: "3f995870-12ea-4d02-b242-ce78abfbf56e" })

Unified query (either ASIN or Reference ID):

const query = `*[_type == "amazon.product" && (
  ($asin != null && asin == $asin) || 
  ($referenceId != null && _id == $referenceId)
)][0]{
  _id, asin, title, brand, price, currency, url, images, features, lastSyncedAt
}`

// Use with ASIN
const productByAsin = await sanityClient.fetch(query, { asin: "B09XFQL45V", referenceId: null })

// Use with Reference ID
const productByRef = await sanityClient.fetch(query, { asin: null, referenceId: "3f995870-12ea-4d02-b242-ce78abfbf56e" })

Multiple Products Array

// Get comparison with multiple Amazon products
const query = `*[_type == "comparison"][0]{
  title,
  amazonProducts[]->{
    asin,
    title,
    brand,
    price,
    currency,
    url,
    images[0].url,
    features[0..2]
  },
  "productCount": count(amazonProducts)
}`

const comparison = await sanityClient.fetch(query)
comparison.amazonProducts.forEach(product => {
  console.log(`${product.title}: ${product.price}`)
})

Filtered Queries

// Find posts featuring specific Amazon product
const postsByProduct = `*[_type == "post" && amazonProduct->asin == $asin]{
  title,
  slug,
  amazonProduct->{
    asin,
    title,
    price
  }
}`

const posts = await sanityClient.fetch(postsByProduct, { asin: 'B0F15TM77B' })

// Find posts with products from specific brand
const postsByBrand = `*[_type == "post" && amazonProduct->brand match $brand + "*"]{
  title,
  amazonProduct->{
    asin,
    title,
    brand,
    price
  }
}`

const applePosts = await sanityClient.fetch(postsByBrand, { brand: 'Apple' })

Product Reviews with Ratings

// Get product reviews with ratings
const reviewsQuery = `*[_type == "review" && defined(amazonProduct)] | order(rating desc){
  title,
  rating,
  pros,
  cons,
  amazonProduct->{
    asin,
    title,
    brand,
    price,
    url,
    images[0].url
  }
}`

const reviews = await sanityClient.fetch(reviewsQuery)

// Get average rating for specific product
const ratingQuery = `{
  "product": *[_type == "amazon.product" && asin == $asin][0]{
    asin,
    title,
    price
  },
  "averageRating": math::avg(*[_type == "review" && amazonProduct->asin == $asin].rating),
  "reviewCount": count(*[_type == "review" && amazonProduct->asin == $asin])
}`

const productStats = await sanityClient.fetch(ratingQuery, { asin: 'B0F15TM77B' })

Advanced Analysis Queries

// Get comparison with price analysis
const analysisQuery = `*[_type == "comparison"][0]{
  title,
  amazonProducts[]->{
    asin,
    title,
    brand,
    price,
    currency
  },
  "lowestPrice": amazonProducts[]->price | order(@) | [0],
  "highestPrice": amazonProducts[]->price | order(@ desc) | [0],
  "brands": array::unique(amazonProducts[]->brand)
}`

const analysis = await sanityClient.fetch(analysisQuery)
console.log(`Price range: ${analysis.lowestPrice} - ${analysis.highestPrice}`)

TypeScript Interfaces

interface PostWithProduct {
  _id: string
  title: string
  slug: string
  amazonProduct: {
    asin: string
    title: string
    brand: string
    price: string
    currency: string
    url: string
    images: Array<{ url: string; width: number; height: number }>
    features: string[]
  }
}

// Use with type safety
const post: PostWithProduct = await sanityClient.fetch(query)

For more GROQ query examples, check the examples/groqQueries.ts file in the plugin.

🎨 React Component for Frontend Display

The plugin includes a flexible React component for displaying Amazon products in your frontend applications.

Quick Start

import AmazonProductDisplay from './AmazonProductDisplay'
import { createClient } from '@sanity/client'

const client = createClient({
  projectId: 'your-project-id',
  dataset: 'production',
  apiVersion: '2025-01-01',
  useCdn: true,
})

// Option 1: Display product from reference field
function BlogPost({ post }) {
  return (
    <div>
      <h1>{post.title}</h1>
      {post.amazonProduct && (
        <AmazonProductDisplay
          product={post.amazonProduct}
          layout="card"
          imageSize="medium"
        />
      )}
    </div>
  )
}

// Option 2: Display product by ASIN lookup
function ProductPage({ asin }) {
  return (
    <AmazonProductDisplay
      asin={asin}
      client={client}
      layout="horizontal"
      imageSize="large"
      onProductClick={(product) => {
        console.log('Product clicked:', product.title)
      }}
    />
  )
}

Component Props

interface AmazonProductDisplayProps {
  // Data source (choose one)
  product?: AmazonProduct          // Direct product data
  asin?: string                    // ASIN for lookup
  referenceId?: string             // Reference ID for lookup
  client?: SanityClient           // Required when using asin or referenceId
  
  // Display options
  showFeatures?: boolean          // Show feature list (default: true)
  showImages?: boolean            // Show product image (default: true)
  showPrice?: boolean             // Show pricing (default: true)
  showBrand?: boolean             // Show brand name (default: true)
  showCTA?: boolean               // Show "View on Amazon" button (default: true)
  
  // Styling options
  layout?: 'horizontal' | 'vertical' | 'card'  // Layout style (default: 'card')
  imageSize?: 'small' | 'medium' | 'large'     // Image size (default: 'medium')
  className?: string              // Custom CSS classes
  ctaText?: string                // Custom CTA button text (default: 'View on Amazon')
  
  // Development options
  debug?: boolean                 // Enable debug mode (default: false)
  
  // Interaction
  onProductClick?: (product: AmazonProduct) => void  // Click handler
}

Usage Examples

🎯 Dual Parameter Support

The component supports 3 different ways to display products:

1. By ASIN Lookup:

import { AmazonProductByASIN } from '@/components/AmazonProductDisplay'
import { sanityClient } from '@/lib/sanity-client'

<AmazonProductByASIN
  asin="B09XFQL45V"
  client={sanityClient}
  layout="card"
  debug={true}
/>

2. By Reference ID Lookup:

import { AmazonProductByReferenceId } from '@/components/AmazonProductDisplay'
import { sanityClient } from '@/lib/sanity-client'

<AmazonProductByReferenceId
  referenceId="3f995870-12ea-4d02-b242-ce78abfbf56e"
  client={sanityClient}
  layout="card"
  debug={true}
/>

3. Unified Component (accepts any parameter):

import AmazonProductDisplay from '@/components/AmazonProductDisplay'
import { sanityClient } from '@/lib/sanity-client'

// Option A: ASIN lookup
<AmazonProductDisplay asin="B09XFQL45V" client={sanityClient} />

// Option B: Reference ID lookup  
<AmazonProductDisplay referenceId="3f995870..." client={sanityClient} />

// Option C: Direct product data
<AmazonProductDisplay product={productData} />

πŸ” Single GROQ Query

All lookup methods use one optimized GROQ query:

*[_type == "amazon.product" && (
  ($asin != null && asin == $asin) || 
  ($referenceId != null && _id == $referenceId)
)][0]{
  _id, asin, title, brand, price, currency, url, images, features, lastSyncedAt
}

4. Blog Post with Featured Product:

function BlogPostWithProduct({ slug }) {
  const [post, setPost] = useState(null)
  
  useEffect(() => {
    const query = `*[_type == "post" && slug.current == $slug][0]{
      title, content,
      amazonProduct->{ asin, title, brand, price, url, images, features }
    }`
    client.fetch(query, { slug }).then(setPost)
  }, [slug])

  return (
    <article>
      <h1>{post?.title}</h1>
      {post?.amazonProduct && (
        <AmazonProductDisplay
          product={post.amazonProduct}
          layout="horizontal"
          imageSize="large"
        />
      )}
    </article>
  )
}

Product Comparison Grid:

function ProductComparison({ comparisonId }) {
  const [comparison, setComparison] = useState(null)
  
  useEffect(() => {
    const query = `*[_type == "comparison" && _id == $comparisonId][0]{
      title,
      amazonProducts[]->{ asin, title, brand, price, url, images, features }
    }`
    client.fetch(query, { comparisonId }).then(setComparison)
  }, [comparisonId])

  return (
    <div>
      <h1>{comparison?.title}</h1>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
        {comparison?.amazonProducts.map((product) => (
          <AmazonProductDisplay
            key={product.asin}
            product={product}
            layout="card"
            showFeatures={false}
          />
        ))}
      </div>
    </div>
  )
}

Direct ASIN Lookup:

function ProductWidget({ asin }) {
  return (
    <div className="bg-gray-50 p-4 rounded">
      <h3>Recommended Product</h3>
      <AmazonProductDisplay
        asin={asin}
        client={client}
        layout="horizontal"
        imageSize="small"
        showFeatures={false}
      />
    </div>
  )
}

Product Review with Rating:

function ProductReview({ reviewId }) {
  const [review, setReview] = useState(null)
  
  useEffect(() => {
    const query = `*[_type == "review" && _id == $reviewId][0]{
      title, rating, pros, cons,
      amazonProduct->{ asin, title, brand, price, url, images }
    }`
    client.fetch(query, { reviewId }).then(setReview)
  }, [reviewId])

  return (
    <div className="grid grid-cols-2 gap-8">
      <AmazonProductDisplay
        product={review?.amazonProduct}
        layout="card"
        ctaText="Buy Now"
      />
      <div>
        <h1>{review?.title}</h1>
        <div className="rating">Rating: {review?.rating}/5</div>
        {/* Review content */}
      </div>
    </div>
  )
}

Styling

The component includes default Tailwind CSS classes and can be customized with:

  • CSS Import:
import './AmazonProductDisplay.css'
  • Custom Classes:
<AmazonProductDisplay
  className="my-custom-product-card shadow-lg"
  // ... other props
/>
  • Layout Variants:
  • card - Card layout with border and shadow
  • horizontal - Side-by-side image and content
  • vertical - Stacked image above content

πŸš€ Quick Start: Frontend Integration

Next.js Copy & Paste Setup

For immediate setup, copy the complete working example:

# 1. Copy the complete Next.js example files
cp examples/complete-nextjs-example/page.tsx src/app/page.tsx
cp examples/components/AmazonProductDisplay.tsx src/components/
cp examples/frontend-integration/sanity-client-setup.ts src/lib/sanity-client.ts

# 2. Install required dependencies
npm install @sanity/client @sanity/image-url

# 3. Configure environment variables
cp examples/complete-nextjs-example/env-template.txt .env.local
# Edit .env.local with your actual Sanity project details

# 4. Start development server
npm run dev

Verify Setup

  • Visit http://localhost:3000 (or your configured port)
  • You should see:
    • βœ… "Product by ASIN Lookup" section
    • βœ… "Product by Reference ID Lookup" section
    • βœ… Debug panels showing component state
    • βœ… Manual fetch buttons for testing

Available Files & Examples

Complete Working Examples:

  • examples/complete-nextjs-example/ - πŸš€ Full Next.js integration
    • page.tsx - Complete page demonstrating ASIN & Reference ID lookups
    • package.json - All required dependencies
    • env-template.txt - Environment variables template
    • SETUP_GUIDE.md - πŸ“– Detailed step-by-step setup guide

Individual Components:

  • examples/components/AmazonProductDisplay.tsx - Main component with dual parameter support
  • examples/components/AmazonProductDisplay.css - Optional styling
  • examples/frontend-integration/sanity-client-setup.ts - Production-ready Sanity client

Schema Integration:

  • examples/productReferenceField.ts - Reusable reference field snippets
  • examples/exampleSchema.ts - Blog post & comparison schema examples
  • examples/groqQueries.ts - Comprehensive GROQ query examples

API Integration (Optional):

  • examples/frontend-integration/amazon-client.ts - Amazon PA-API client
  • examples/frontend-integration/nextjs-api-route.ts - API route examples
  • examples/frontend-integration/fetch-product-api-route.ts - Product fetch API

Troubleshooting:

  • examples/environment-setup.md - Environment setup & common issues
  • Built-in debug mode in components

🎯 Usage

1. Configure Amazon Settings

  • Open your Sanity Studio

  • Go to "Amazon Settings" from the sidebar

  • Fill in your Amazon PA-API credentials:

    • Region: Select your marketplace (US, UK, DE, etc.)
    • Access Key: Your PA-API access key
    • Secret Key: Your PA-API secret key
    • Partner Tag: Your Amazon Associate tag
    • Test ASIN: An ASIN for testing (e.g., B0F15TM77B)
    • Cache Hours: Duration to cache results (1-168 hours)
  • Click "Test API Connection" to verify your setup

2. Create Amazon Products

  • Go to "Amazon Products" from the sidebar

  • Click "Add new" to create a product document

  • Enter an ASIN number in the ASIN field

  • Navigate to the "Actions" tab

  • Click "Fetch from Amazon" button

  • The document will be auto-populated with:

    • Product title (with auto-generated slug)
    • Brand name
    • Pricing information
    • Primary product image
    • Product description
    • Product type and status
    • Amazon permalink
    • Last sync timestamp
  • Review and edit the data as needed

  • Click "Publish" when ready

NEW: Product titles now automatically generate URL-friendly slugs!

https://share.cleanshot.com/n2tnCdSDwsW11cwYH7dq

Creating a new Amazon product document

3. Manual Entry

You can also manually enter product information without fetching from Amazon. All fields are editable.

πŸ“‹ Schema Reference

Amazon Settings (amazon.settings)

API Settings:

  • region - Amazon marketplace region
  • accessKey - PA-API access key
  • secretKey - PA-API secret key
  • partnerTag - Amazon Associate tag
  • asinNumber - Test ASIN for API validation
  • cacheHours - Cache duration (1-168 hours)

Display Settings:

  • showTitle - Show/hide product title
  • showImage - Show/hide product image
  • showFeatures - Show/hide feature list
  • showPrice - Show/hide pricing
  • showCtaLink - Show/hide CTA link

Actions:

  • "Test API Connection" - Verify credentials with real-time form validation
  • "Debug Document" - View document state and form values

NEW: Real-time form validation using useFormValue - buttons enable/disable instantly as you type!

https://share.cleanshot.com/P2LbmkdNCJcwJFf14CHC

Amazon Settings actions panel with Test API Connection button

Amazon Product (amazon.product)

Product Information:

  • asin - Amazon Standard Identification Number
  • title - Product title
  • slug - Auto-generated URL-friendly slug from title
  • brand - Brand/manufacturer name
  • permalink - Direct Amazon product URL
  • shortDescription - Product description (HTML stripped)
  • type - Product type: 'simple', 'variable', 'grouped', 'external'
  • featured - Featured product status
  • sku - Stock keeping unit

Pricing:

  • regularPrice - Regular price
  • salePrice - Sale price (if on sale)
  • price - Current selling price

Media & Ratings:

  • primaryImage - Primary product image URL
  • averageRating - Average customer rating (0-5)
  • ratingCount - Number of customer ratings
  • stockStatus - Stock status: 'instock', 'outofstock', 'onbackorder'

Metadata:

  • lastSyncedAt - Timestamp of last Amazon sync

Actions:

  • "Fetch from Amazon" - Auto-populate from Amazon API

πŸ†• Recent Improvements (Latest Update)

✨ What's New

  • Real-time Form Validation: Settings now use useFormValue for instant feedback and button state updates
  • Streamlined Schema: Simplified product schema with essential fields only
  • Component Consolidation: Removed redundant components for cleaner architecture
  • Secure Configuration: Environment variable-based API endpoint configuration
  • Auto-slug Generation: Automatic slug generation from product titles

πŸ”§ Key Changes Made

  • AmazonSettingsActions.tsx:

    • Replaced complex state management with real-time form values
    • Uses useFormValue hooks for immediate validation
    • Buttons enable/disable in real-time as you type
  • Schema Simplification:

    • Removed complex fields like description (Portable Text)
    • Added essential fields like slug, type, featured, stockStatus
    • Streamlined pricing fields for better usability
  • Component Cleanup:

    • Removed AmazonAsinInput.tsx (redundant functionality)
    • Removed AmazonProductFetch.tsx (unused component)
    • Kept AmazonFetchButton.tsx as the primary fetch component
  • Configuration System:

    • Added src/lib/config.ts for centralized environment variable handling
    • Replaced hardcoded URLs with configurable endpoints
    • Added validation for required environment variables

πŸ—οΈ Component Architecture

Current Components

The plugin now uses a streamlined component architecture:

  • AmazonSettingsActions.tsx - Settings actions with real-time validation
  • AmazonFetchButton.tsx - Primary fetch component for product documents
  • Configuration System - Centralized environment variable handling

Removed Components

The following components were removed for cleaner architecture:

  • ❌ AmazonAsinInput.tsx - Redundant functionality
  • ❌ AmazonProductFetch.tsx - Unused component

Component Responsibilities

  • AmazonSettingsActions: Handles API testing and debugging with real-time form values
  • AmazonFetchButton: Fetches product data and updates documents
  • Config System: Manages environment variables and API endpoints

πŸ› οΈ Development

Build the Plugin

cd plugins/@multidots/sanity-plugin-amazon-product-sync
npm install
npm run build

Start API Server

cd your-frontend-app
npm install
npm run dev

Start Sanity Studio

cd your-sanity-project
npm run dev

πŸ”§ Troubleshooting

Common Issues

Frontend Component Issues

  • "No product available" despite correct ASIN

    • Problem: Component shows debug info but never fetches data
    • Solution: Enable debug mode and check browser console
    <AmazonProductByASIN
      asin="B09XFQL45V"
      client={sanityClient}
      debug={true} // Shows debug panel with manual fetch button
    />
    
    • Click the "πŸ”„ Manual Fetch" button to test the Sanity client directly
  • Environment variables not working

    • Problem: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID is undefined
    • Solution: Ensure .env.local exists with correct variables
    # .env.local
    NEXT_PUBLIC_SANITY_PROJECT_ID=your-project-id
    NEXT_PUBLIC_SANITY_DATASET=production
    SANITY_API_TOKEN=your-token
    
    • Use NEXT_PUBLIC_ prefix for client-side variables
  • CORS errors when fetching from Sanity

    • Problem: Browser blocks requests to Sanity API
    • Solution: Use correct client configuration
    export const sanityClient = createClient({
      projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
      dataset: 'production',
      apiVersion: '2025-01-01',
      useCdn: true, // Important for client-side
      // NO token needed for public documents
    })
    
  • useEffect not triggering automatically

    • Problem: Component doesn't fetch data on mount
    • Solution: Add debug logging to see which conditions fail
    useEffect(() => {
      console.log('useEffect conditions:', {
        hasInitialProduct: !!initialProduct,
        hasAsin: !!asin,
        hasClient: !!client
      })
    }, [asin, client, initialProduct])
    

API Issues

  • "Amazon API credentials not configured"

    • Verify your Sanity API token has read access to amazon.settings
    • Check that amazon.settings document exists in Sanity Studio
    • Ensure token is available server-side only
  • "InvalidSignature" error

    • Check your PA-API access key and secret key
    • Verify your system clock is accurate
    • Ensure you're using the correct region
  • Product documents not accessible

    • Test with direct GROQ query:
    curl -X POST "https://YOUR_PROJECT_ID.api.sanity.io/v2025-01-01/data/query/production" \
      -H "Content-Type: application/json" \
      -d '{"query": "*[_type == \"amazon.product\"][0]{asin, title}"}'
    
    • Ensure documents are published (not drafts)
    • Check document permissions in Sanity Studio

Debug Mode

The component includes built-in debugging tools:

// Enable debug mode to see detailed information
<AmazonProductDisplay
  asin="B09XFQL45V"
  client={sanityClient}
  debug={process.env.NODE_ENV === 'development'}
/>

Debug features:

  • Console logging of all fetch attempts
  • Visual debug panel showing component state
  • Manual fetch button to test Sanity client
  • Full product data logging

Development Workflow

  • Test Sanity Connection First

    import { testSanityConnection } from './lib/sanity-client-setup'
    
    testSanityConnection('B09XFQL45V').then(result => {
      console.log('Sanity test:', result)
    })
    
  • Create Test Products See examples/environment-setup.md for the script

  • Use Debug Mode

    <AmazonProductByASIN debug={true} />
    
  • Check Browser Console

    • Look for 🎬, πŸ”, πŸ“¦, βœ…, ❌ emoji logs
    • Manual fetch button provides direct testing

πŸ“š Additional Resources

πŸ“„ License

MIT

🀝 Support

For issues and questions:

  • Check the troubleshooting section above
  • Verify your configuration matches the examples
  • Check browser console and API server logs
  • Ensure your Amazon PA-API account is active

Note: This plugin requires an active Amazon Product Advertising API account and valid credentials. The PA-API has rate limits and approval requirements.

Keywords

sanity

FAQs

Package last updated on 22 Aug 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

About

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.

  • Terms
  • Privacy
  • Security

Made with ⚑️ by Socket Inc

U.S. Patent No. 12,346,443 & 12,314,394. Other pending.