npm package: @posty5/amazon-product-scraper
Description: Scrape Amazon product information — name, price, images, rating, reviews, estimated sales. Optional currency conversion.
Latest version: 1.0.0

# @posty5/amazon-product-scraper

Scrape Amazon product pages and extract structured product data — name, price, images, rating, reviews, estimated sales. Optional currency conversion with user-provided exchange rates. Built with [Axios](https://axios-http.com/) and [Cheerio](https://cheerio.js.org/).

[![npm version](https://img.shields.io/npm/v/@posty5/amazon-product-scraper)](https://www.npmjs.com/package/@posty5/amazon-product-scraper)
[![license](https://img.shields.io/npm/l/@posty5/amazon-product-scraper)](./LICENSE)

---

## 🌟 What is @posty5/amazon-product-scraper?

**@posty5/amazon-product-scraper** is a TypeScript package that scrapes Amazon product pages and returns structured data. It supports:

1. **Single Scrape** — Scrape one product URL and get all its data
2. **Batch Scrape** — Scrape multiple products with concurrency and delay control
3. **Currency Conversion** — Optionally convert prices using your own exchange rate map

**Extracted Product Data:**

```typescript
interface Product {
  name?: string;
  description?: string;
  images: string[];
  price?: number;
  currency?: string;
  rating?: number;
  reviews_count?: number;
  estimated_sales?: number;
}
```

**Use Cases:**

- 🛒 Price monitoring and comparison
- 📊 Market research and product analytics
- 💰 Multi-currency product catalogs
- 📈 Sales estimation and trend tracking
- 🔍 Product data aggregation

---

## 📦 Installation

```bash
npm install @posty5/amazon-product-scraper
```

---

## 🚀 Quick Start

### Scrape a Single Product

```typescript
import { scrapeProduct } from '@posty5/amazon-product-scraper';

const result = await scrapeProduct({
  url: 'https://www.amazon.com/dp/B0D2Q9317K',
});

if (result.status === 'ok') {
  console.log(result.product);
}
```

### Scrape with Currency Conversion

```typescript
import { scrapeProduct } from '@posty5/amazon-product-scraper';

const result = await scrapeProduct({
  url: 'https://www.amazon.com/dp/B0D2Q9317K',
  targetCurrency: 'EGP',
  currencyRates: { USD: 1, EGP: 50.5, EUR: 0.92 },
});

// Price is automatically converted from USD → EGP
console.log(result.product?.price);    // 2525 (50 * 50.5)
console.log(result.product?.currency); // "EGP"
```

### Batch Scrape

```typescript
import { scrapeProducts } from '@posty5/amazon-product-scraper';

const batch = await scrapeProducts({
  urls: [
    'https://www.amazon.com/dp/B0D2Q9317K',
    'https://www.amazon.com/dp/B0BSHF7WHW',
  ],
  concurrency: 1,
  delayMs: 3000,
});

console.log(`${batch.succeeded}/${batch.total} succeeded`);
```

---

## 📚 API Reference

### `scrapeProduct(config)`

Scrape a single Amazon product page.

**Returns:** `Promise<ScrapeResult>`

```typescript
import { scrapeProduct } from '@posty5/amazon-product-scraper';

const result = await scrapeProduct({
  url: 'https://www.amazon.com/dp/B0D2Q9317K',
  locale: 'ar_EG',
  targetCurrency: 'EGP',
  currencyRates: { USD: 1, EGP: 50.5 },
  timeout: 20000,
  maxRetries: 2,
  captchaBackoffMs: 10000,
});

console.log(result);
// {
//   url: 'https://www.amazon.com/dp/B0D2Q9317K',
//   status: 'ok',
//   product: {
//     name: 'Product Name...',
//     description: 'Product description...',
//     images: ['https://...', 'https://...'],
//     price: 2525,
//     currency: 'EGP',
//     rating: 4.5,
//     reviews_count: 1234,
//     estimated_sales: 5000,
//   }
// }
```

---

### `scrapeProducts(config)`

Scrape multiple Amazon product pages with concurrency and delay control.

**Returns:** `Promise<ScrapeBatchResult>`

```typescript
import { scrapeProducts } from '@posty5/amazon-product-scraper';

const batch = await scrapeProducts({
  urls: [
    'https://www.amazon.com/dp/B0D2Q9317K',
    'https://www.amazon.com/dp/B0BSHF7WHW',
    'https://www.amazon.de/dp/B0EXAMPLE',
  ],
  locale: 'en_US',
  concurrency: 2,
  delayMs: 3000,
  targetCurrency: 'USD',
  currencyRates: { USD: 1, EUR: 0.92, GBP: 0.79 },
});

console.log(batch);
// {
//   total: 3,
//   succeeded: 2,
//   failed: 1,
//   results: [
//     { url: '...', status: 'ok', product: { ... } },
//     { url: '...', status: 'ok', product: { ... } },
//     { url: '...', status: 'error', error: 'Captcha detected...' },
//   ]
// }
```

---

## ⚙️ Configuration

### Scrape Options (`ScrapeProductConfig`)

Used by `scrapeProduct()`.

| Option | Type | Default | Description |
|---|---|---|---|
| `url` | `string` | **(required)** | Amazon product URL |
| `locale` | `string` | `'en_US'` | Accept-Language locale (e.g. `'ar_EG'`, `'de_DE'`) |
| `targetCurrency` | `string` | — | Target currency ISO code for price conversion |
| `currencyRates` | `CurrencyRates` | — | Exchange rate map (**required** when `targetCurrency` is set) |
| `timeout` | `number` | `20000` | Request timeout in milliseconds |
| `maxRetries` | `number` | `1` | Maximum retries on captcha detection |
| `captchaBackoffMs` | `number` | `10000` | Backoff in ms before retrying after captcha |

### Batch Options (`ScrapeProductsConfig`)

Used by `scrapeProducts()`. Includes all options from `ScrapeProductConfig` (except `url`) plus:

| Option | Type | Default | Description |
|---|---|---|---|
| `urls` | `string[]` | **(required)** | Array of Amazon product URLs |
| `concurrency` | `number` | `1` | Number of products to scrape in parallel |
| `delayMs` | `number` | `3000` | Delay in ms between batches |

---

## 💱 Currency Conversion

Currency conversion is **optional** and fully controlled by you. The package never makes external API calls for exchange rates — you provide the rates yourself.

### How It Works

1. The scraper detects the currency from the product page (symbols, codes, URL domain)
2. If you provide `targetCurrency` + `currencyRates`, the price is converted automatically
3. If you don't provide them, the price is returned in the original currency

### Providing Exchange Rates

```typescript
// All rates relative to the same base (e.g. USD = 1)
const rates = {
  USD: 1,
  EUR: 0.92,
  GBP: 0.79,
  EGP: 50.5,
  SAR: 3.75,
  AED: 3.67,
  JPY: 149.5,
  INR: 83.1,
};

const result = await scrapeProduct({
  url: 'https://www.amazon.de/dp/B0EXAMPLE',  // Price in EUR
  targetCurrency: 'USD',
  currencyRates: rates,
});
// Price is converted: EUR → USD
```

### Supported Currencies

The following currencies are auto-detected from Amazon product pages:

| Region | Currencies |
|---|---|
| **Americas** | USD, CAD, BRL, MXN |
| **Europe** | EUR, GBP, SEK, NOK, DKK, CHF, PLN, CZK, HUF, RON, TRY |
| **Middle East** | SAR, EGP, AED, QAR, KWD, BHD, OMR, JOD, ILS |
| **Asia Pacific** | JPY, INR, KRW, CNY, TWD, HKD, SGD, AUD, NZD, PKR, PHP, THB, MYR, IDR, VND |
| **Africa** | ZAR |

---

## 🔧 Advanced Usage

### Utility Functions

The package also exports individual utility functions for advanced use:

```typescript
import {
  detectCurrency,    // Detect currency from price text + URL
  convertPrice,      // Convert between currencies using a rate map
  parseProduct,      // Parse cheerio-loaded HTML
  isCaptchaPage,     // Check if HTML is a captcha page
  buildAcceptLanguage, // Build Accept-Language header from locale
} from '@posty5/amazon-product-scraper';
```

### Detect Currency Manually

```typescript
import { detectCurrency } from '@posty5/amazon-product-scraper';

detectCurrency('$49.99', 'https://www.amazon.com/dp/...');   // 'USD'
detectCurrency('€49.99');                                     // 'EUR'
detectCurrency('EGP 500');                                    // 'EGP'
detectCurrency('A$79.99');                                    // 'AUD'
detectCurrency('$49.99', 'https://www.amazon.ca/dp/...');    // 'CAD'
```

### Convert Price Manually

```typescript
import { convertPrice } from '@posty5/amazon-product-scraper';

const rates = { USD: 1, EUR: 0.92, EGP: 50.5 };

convertPrice(100, 'USD', 'EGP', rates);  // 5050
convertPrice(92,  'EUR', 'USD', rates);  // 100
```

### Using with Different Amazon Domains

The scraper works with any Amazon domain. Use the `locale` option for proper language headers:

```typescript
// Amazon US (English)
await scrapeProduct({ url: 'https://www.amazon.com/dp/B0EXAMPLE' });

// Amazon Germany (German)
await scrapeProduct({ url: 'https://www.amazon.de/dp/B0EXAMPLE', locale: 'de_DE' });

// Amazon Japan (Japanese)
await scrapeProduct({ url: 'https://www.amazon.co.jp/dp/B0EXAMPLE', locale: 'ja_JP' });

// Amazon Egypt (Arabic)
await scrapeProduct({ url: 'https://www.amazon.eg/dp/B0EXAMPLE', locale: 'ar_EG' });

// Amazon Saudi Arabia (Arabic)
await scrapeProduct({ url: 'https://www.amazon.sa/dp/B0EXAMPLE', locale: 'ar_SA' });
```

---

## 📂 Project Structure

```
src/
├── index.ts              # Public API — exports functions + types
├── test-app.ts           # Runnable test app
├── config/
│   ├── types.ts          # All TypeScript interfaces
│   ├── resolve.ts        # Default filling & validation
│   └── index.ts          # Barrel export
├── scraper/
│   ├── http.ts           # User-agent rotation, axios fetch, retry
│   ├── parser.ts         # Cheerio HTML → Product extraction
│   ├── captcha.ts        # Bot-page detection
│   └── index.ts          # Barrel export
└── currency/
    ├── detect.ts         # Price text → ISO currency code
    ├── convert.ts        # Pure currency conversion
    └── index.ts          # Barrel export
```

---

## 🧪 Test App

A built-in test app demonstrates all features:

```bash
npm run test-app
```

The test app runs three scenarios:
1. Scrape a single product (no currency conversion)
2. Scrape a single product with USD → EGP conversion
3. Batch scrape multiple products

---

## 💻 Requirements

- **Node.js:** >= 18.0.0
- **TypeScript:** Full type definitions included
- **Dependencies:** `axios`, `cheerio`

---

## 📖 Resources

- **Website:** [https://posty5.com](https://posty5.com)
- **Dashboard:** [https://studio.posty5.com](https://studio.posty5.com)
- **GitHub:** [https://github.com/Posty5/amazon-product-scraper](https://github.com/Posty5/amazon-product-scraper)
- **Support:** [https://posty5.com/contact-us](https://posty5.com/contact-us)

---

## 🆘 Support

- **Contact Us:** [https://posty5.com/contact-us](https://posty5.com/contact-us)
- **GitHub Issues:** [Report bugs or request features](https://github.com/Posty5/amazon-product-scraper/issues)

---

## 🤝 Contributing

Contributions are welcome! Please follow these steps:

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/amazing-feature`
3. Make your changes
4. Commit your changes: `git commit -m 'Add amazing feature'`
5. Push to the branch: `git push origin feature/amazing-feature`
6. Submit a pull request

---

## 📄 License

MIT License - see [LICENSE](./LICENSE) file for details.

---

Made with ❤️ by the [Posty5](https://posty5.com) team