# Gmarket KR  $1💰 URL Keyword and Review Scraper (`abotapi/gmarket-global-scraper`) Actor

Scrape product listings and customer reviews from Gmarket.co.kr into clean JSON datasets. Supports keyword search, product URLs, or review-only mode by product ID. Lightweight, free-tier friendly, and runs without a browser.

- **URL**: https://apify.com/abotapi/gmarket-global-scraper.md
- **Developed by:** [Abot API](https://apify.com/abotapi) (community)
- **Categories:** E-commerce, Developer tools, Automation
- **Stats:** 5 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Gmarket Global Scraper

> Sample shape below is illustrative; values are placeholders, not from a live listing.

Pull product listings AND customer reviews from Gmarket Global (the English-language storefront of one of Korea's biggest marketplaces) into a clean JSON dataset. Two modes: keyword search or URL paste. One toggle flips the same flow from "one record per product" to "one record per review." Detail enrichment is on by default and adds the full seller disclosure (business name, manager, customer-service phone, business registration, e-commerce registration).

### Why this scraper

- 25+ product fields per record, with optional detail enrichment that adds the legally-mandated Korean seller info (company name, manager name, customer-service phone, business registration number, e-commerce sales registration).
- Flip "Reviews only" to scrape reviews of every matching product instead of the products themselves.
- English titles by default (the global storefront serves English).
- KRW and USD prices side by side, plus original-vs-sale price and discount percent.
- Every record also carries a `raw` block with the verbatim upstream API response, so no field is ever silently dropped.
- Datacenter proxy works out of the box on the free Apify plan.

### Data you get

#### Product records (default)

| Field | Example |
| --- | --- |
| goodsCode | "0000000001" |
| title | "Sample Product Title" |
| linkUrl | "https://mg.gmarket.co.kr/Item?goodscode=0000000001" |
| imageUrl | "https://gdimg.gmarket.co.kr/0000000001/still/280?ver=0" |
| additionalImages | \["https://gdimg.gmarket.co.kr/.../shop\_img/000/000/0000000001.jpg"] |
| sellPriceKrw | 22800 |
| originalPriceKrw | "22,800" |
| salePriceKrw | "22,800" |
| currencyPrice | "$15.75" |
| discountRate | "0" |
| wasPriceKrw | 41490 (numeric, `null` when not on special) |
| currentPriceKrw | 22800 (numeric current/paying price, always populated) |
| savingsAmountKrw | 5200 (numeric, `null` when not on special) |
| discountRatePercent | 21 (numeric mirror of `discountRate`, `null` when not on special) |
| isOnSpecial | false |
| isBigSmilePromo | false (correctly wired from the API's `IsBigSmileItem`; see note below) |
| bigSmileImageUrl | null |
| isSponsored | false |
| isFreeShipping | true |
| deliveryInfo | "Free" |
| deliveryFee | "0" |
| sellerCustNo | "000000000" |
| miniShopHandle | "samplestore" |
| miniShopUrl | "https://mg.gmarket.co.kr/samplestore" |
| categoryCodeL | "100000000" |
| categoryCodeM | "200000000" |
| categoryCodeS | "300000000" |
| overseaDeliveryAvailable | true |
| isBigSmile | false |
| isAdult | false |
| translation.english | true |
| translation.chinese | true |
| translation.japanese | false |
| raw | `{ ...full upstream Item JSON... }` |
| scrapedAt | "2026-01-01T00:00:00.000Z" |

When `fetchDetails` is on (the default), each record also carries:

| Field | Example |
| --- | --- |
| descriptionText | "Up to 3,000 chars of cleaned product description." |
| brand | "SampleBrand" |
| sellerCompanyName | "Sample Trading Co., Ltd." |
| sellerManagerName | "John Doe" |
| sellerPhone | "02-0000-0000" |
| sellerBusinessNumber | "000-00-00000" |
| sellerEcommerceNumber | "0000-Seoul-0000" |
| sellerInfo | `{ ...full upstream SellerInfo JSON: 15 fields... }` |

### Specials, was-price & discount

Every product already carries a genuine, per-product was/current price and discount rate (verified
live, never fabricated): a was price, a current price, and the site's own computed discount % plus the
exact KRW savings. The numeric fields below are additive and derived from data the scrape already
collects for each product, so they add no extra work and no extra cost:

- `wasPriceKrw` / `savingsAmountKrw` / `discountRatePercent` populate **only when the item is genuinely
  discounted** (mirrors the existing `discountRate` field); on an ordinary, non-discounted item they are
  `null` — verified live on a `laptop` search (all `0` in `discountRate`, `wasPriceKrw`/`savingsAmountKrw`
  correctly `null`).
- `currentPriceKrw` is the numeric price the customer actually pays right now (parsed `SalePrice`); it is
  always populated, discounted or not.
- Verified live on a `phone case` search (majority of cards discounted): e.g. was ₩24,000 → now ₩18,800,
  save ₩5,200 (21%); was ₩10,000 → now ₩6,900, save ₩3,100 (31%) — matching the site's own math exactly.

**Specials-category taxonomy — verified, not fabricated.** Gmarket Global was checked directly for any
Super Deals / Big Sale / discount-collection surface **beyond** what's already scraped. None exists:

- Sort options are only relevance/popularity, newest, price asc/desc, and rating — no discount- or
  deal-based sort.
- There is no separate deals/specials collection or category to browse; the only promotion-scoped
  filter is the sitewide "BigSmile" promotion, which this actor **already** exposes as the
  `bigSmileOnly` input (default off — this already satisfies "specials as an opt-in, never auto-run").
- `isBigSmilePromo` and `bigSmileImageUrl` are additive fields that correctly reflect a product's real
  BigSmile promotion status (the pre-existing `isBigSmile` output field reads a differently-named key
  that never carries a value, so it is always `false`; left unchanged to avoid revaluing an existing
  field — `isBigSmilePromo` is the accurate signal going forward). `isSponsored` is an additional real,
  non-fabricated per-product signal (sponsored/ad placement).
- BigSmile campaigns are time/keyword-gated — across several unrelated keyword probes during
  verification, `isBigSmilePromo=true` returned 0 items each time. The fields still populate correctly
  whenever a live BigSmile campaign covers the searched keyword; they are not fabricated when it doesn't.

#### Review records (when `reviewsOnly` is on)

The actor still uses your keyword or URL input to discover products, but pushes one record per review instead of one per product.

| Field | Example |
| --- | --- |
| productGoodsCode | "0000000001" |
| productLinkUrl | "https://mg.gmarket.co.kr/Item?goodscode=0000000001" |
| reviewId | "100000000" |
| authorNickname | "abc\*\*\*\*" (Gmarket-masked) |
| authorLoginId | "abc1234" (the un-masked login, passed through verbatim) |
| authorCustNo | "0000000000" |
| authorCountryCode | "KR" |
| rating | 9 |
| ratingMax | 10 |
| deliveryRating | 5 |
| title | "Sample review title" |
| comment | "Sample comment body" |
| titleEnglish | "Sample title translated" |
| commentEnglish | "Sample comment translated" |
| reviewDate | "2026-01-01T00:00:00.000Z" |
| reviewDateText | "2026.01.01" |
| hasPhotos | true |
| photoUrls | \["https://bampic.gmarket.co.kr/..."] |
| variantInfo | "Color: Black \[1ea]" |
| sellerReply | null |
| sellerReplyDate | null |
| isPowerReviewer | true |
| readCount | 0 |
| raw | `{ ...full upstream review JSON, 40 fields... }` |
| scrapedAt | "2026-01-01T00:00:00.000Z" |

### How to use

Keyword search, default settings (detail enrichment on, unlimited pages capped at 20 records by `maxListings`):

```json
{
  "mode": "search",
  "keywords": ["laptop"]
}
```

Keyword search with price band, oversea-only, multi-keyword, deeper pagination:

```json
{
  "mode": "search",
  "keywords": ["headphones", "earbuds"],
  "minPrice": 10000,
  "maxPrice": 100000,
  "overseaDeliveryOnly": true,
  "maxPages": 3
}
```

URL mode (paste any Gmarket Global search URL with whatever filters you want):

```json
{
  "mode": "url",
  "urls": ["https://mg.gmarket.co.kr/Search/Search?keyword=phone&minPrice=50000&maxPrice=500000"],
  "maxPages": 2
}
```

Reviews only (pulls reviews of every product matching your search; caps total reviews at maxListings):

```json
{
  "mode": "search",
  "keywords": ["laptop"],
  "reviewsOnly": true,
  "maxReviewsPerProduct": 20,
  "maxListings": 100
}
```

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| mode | enum | "search" | "search" uses keywords + filters; "url" uses pasted search-result URLs |
| keywords | array of strings | \["laptop"] | One or more product keywords; English or Korean both work. Search mode only |
| minPrice | integer | 0 | Min sale price in KRW. 0 = no minimum |
| maxPrice | integer | 0 | Max sale price in KRW. 0 = no maximum |
| overseaDeliveryOnly | boolean | false | Restrict to items that ship outside Korea |
| bigSmileOnly | boolean | false | Restrict to BigSmile sitewide promotion items |
| urls | array of strings | \[...] | One entry per search. URL mode only |
| reviewsOnly | boolean | false | Push one record per review instead of one per product. Uses the same search/URL flow to discover products first |
| maxReviewsPerProduct | integer | 50 | Reviews-only mode: stop after N reviews per product (20 per page) |
| maxPages | integer | 0 | Pages to walk per keyword / URL (60 items per page). 0 = unlimited — walk all pages until the site runs out of results |
| maxListings | integer | 20 | Cap on TOTAL records output (products or reviews depending on `reviewsOnly`). Keeps a default run small; set 0 to walk the entire catalogue (unlimited) |
| fetchDetails | boolean | true | Fetch product detail pages to populate description, brand, and the full seller disclosure. Turn off for a leaner, faster scrape |
| resumeFromRunId | string | (empty) | Paste a previous run ID or dataset ID to continue a large walk-all pull: products/reviews already saved by that run are loaded before scraping starts and skipped, so this run only appends new records |
| proxy | proxy | Apify Datacenter | Network. Datacenter works fine; residential rarely needed |

### Send results into your apps (MCP connectors)

Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step **after** the scrape — the Apify dataset is never changed.

**What gets written to the connector:** a condensed, human-readable **summary** of each record — not the full JSON. Each item becomes one entry with a **title** and its key fields flattened to plain text. The **complete record always stays in the Apify dataset**.

1. Authorize a connector once under **Apify → Settings → Integrations** (Notion, Linear, Airtable, or Apify).
2. Select it in the **"Pipe results into your apps"** input field. (If the picker is empty, you haven't authorized a connector yet.)
3. For **Notion**, also set `notionParentPageUrl` to the page where items should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

### Output example (product, with fetchDetails: true)

```json
{
  "goodsCode": "0000000001",
  "title": "Sample Product Title",
  "linkUrl": "https://mg.gmarket.co.kr/Item?goodscode=0000000001",
  "imageUrl": "https://gdimg.gmarket.co.kr/0000000001/still/280?ver=0",
  "sellPriceKrw": 22800,
  "currencyPrice": "$15.75",
  "discountRate": "0",
  "wasPriceKrw": null,
  "currentPriceKrw": 22800,
  "savingsAmountKrw": null,
  "discountRatePercent": null,
  "isOnSpecial": false,
  "isBigSmilePromo": false,
  "bigSmileImageUrl": null,
  "isSponsored": false,
  "sellerCompanyName": "Sample Trading Co., Ltd.",
  "sellerManagerName": "John Doe",
  "sellerPhone": "02-0000-0000",
  "sellerBusinessNumber": "000-00-00000",
  "sellerEcommerceNumber": "0000-Seoul-0000",
  "sellerInfo": {
    "CompanyName": "Sample Trading Co., Ltd.",
    "ManagerName": "John Doe",
    "HelpDeskStartDate": "10",
    "HelpDeskEndDate": "16",
    "HelpDeskTelNo": "02-0000-0000",
    "CompanyNo": "000-00-00000",
    "EcomerceNo": "0000-Seoul-0000",
    "SellerGrade": "A1",
    "DealerSatisGrade": "AA"
  },
  "descriptionText": "Sample product description text.",
  "brand": "SampleBrand",
  "overseaDeliveryAvailable": true,
  "translation": { "english": true, "chinese": true, "japanese": false },
  "scrapedAt": "2026-01-01T00:00:00.000Z"
}
```

### Plan requirement

Works on any Apify plan, including the Free plan, because the default proxy is Apify Datacenter. If you ever see zero results from Apify Datacenter, switch the proxy to Apify Residential (Starter plan or higher) and try again.

# Actor input Schema

## `mode` (type: `string`):

Pick how you want to drive the scrape. 'Keyword search' uses your keywords + filters; 'Paste URLs' uses Gmarket Global search-result URLs you already have.

## `keywords` (type: `array`):

One or more product keywords to search for (English or Korean both work). One run = one search per keyword × applied filters. Only used when mode is 'Keyword search'.

## `minPrice` (type: `integer`):

Minimum sale price in Korean Won. Leave 0 for no minimum. Example: 10000 (≈ $7 USD).

## `maxPrice` (type: `integer`):

Maximum sale price in Korean Won. Leave 0 for no maximum. Example: 100000 (≈ $70 USD).

## `overseaDeliveryOnly` (type: `boolean`):

When on, returns only items that ship outside Korea. Verified to narrow results by ~75% on broad queries.

## `bigSmileOnly` (type: `boolean`):

When on, returns only items participating in the BigSmile sitewide promotion.

## `urls` (type: `array`):

One or more Gmarket Global search-result URLs (must contain /Search/Search?keyword=...). Filter fields above are ignored in this mode; the URL's own query parameters are the filters. Forward pagination starts from the page in the URL.

## `reviewsOnly` (type: `boolean`):

When on, the actor still uses your keyword search or pasted URLs to discover products, but pushes one record per REVIEW instead of one record per product. Pair with maxReviewsPerProduct to cap how deep to walk each product.

## `maxReviewsPerProduct` (type: `integer`):

Only applies when 'Reviews only' is on. Stop after this many reviews per product. The API serves 20 per page; 50 = up to 3 pages each. Set 0 to walk every review the product has. Reviews come back in Gmarket's default order (typically featured first; the storefront does not expose a sort control).

## `maxPages` (type: `integer`):

How many pages to walk per keyword (or per URL). The API serves 60 items per page, so 1 page returns up to 60 products. 0 = unlimited (walk all pages until the site runs out of results).

## `maxListings` (type: `integer`):

Stop the whole run once this many unique records have been collected. When 'Reviews only' is off this counts products; when on it counts reviews across all products. Default 20 keeps a run small; set 0 to walk the entire catalogue (unlimited).

## `fetchDetails` (type: `boolean`):

When on, makes one extra fetch per item to capture description text, brand, and full seller info (company name, manager, customer-service phone, business number, e-commerce sales registration). Turn off for a faster, leaner scrape with only the search-listing fields.

## `resumeFromRunId` (type: `string`):

Optional. Paste a previous run ID or dataset ID to continue a large walk-all pull: products/reviews already saved by that run are loaded before scraping starts and skipped, so this run only appends new records. Leave empty for a normal fresh run.

## `proxy` (type: `object`):

Apify Datacenter is the default and is free-tier compatible. Residential is rarely needed for this site.

## `mcpConnectors` (type: `array`):

Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON — the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com).

## `notionParentPageUrl` (type: `string`):

URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.

## `maxNotifyListings` (type: `integer`):

Cap on items written to each connector per run. Does not affect the dataset.

## Actor input object example

```json
{
  "mode": "search",
  "keywords": [
    "laptop"
  ],
  "minPrice": 0,
  "maxPrice": 0,
  "overseaDeliveryOnly": false,
  "bigSmileOnly": false,
  "urls": [
    "https://mg.gmarket.co.kr/Search/Search?keyword=laptop"
  ],
  "reviewsOnly": false,
  "maxReviewsPerProduct": 50,
  "maxPages": 0,
  "maxListings": 20,
  "fetchDetails": true,
  "proxy": {
    "useApifyProxy": true
  },
  "maxNotifyListings": 50
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

## `reviews` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "keywords": [
        "laptop"
    ],
    "urls": [
        "https://mg.gmarket.co.kr/Search/Search?keyword=laptop"
    ],
    "proxy": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("abotapi/gmarket-global-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "keywords": ["laptop"],
    "urls": ["https://mg.gmarket.co.kr/Search/Search?keyword=laptop"],
    "proxy": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("abotapi/gmarket-global-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "keywords": [
    "laptop"
  ],
  "urls": [
    "https://mg.gmarket.co.kr/Search/Search?keyword=laptop"
  ],
  "proxy": {
    "useApifyProxy": true
  }
}' |
apify call abotapi/gmarket-global-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=abotapi/gmarket-global-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/kenHH2gL6JIDgkXMi/builds/tKtF2m59IDRFVabWw/openapi.json
