# Woo GTIN Fallback Review (`remarkable_whipscorpion/woo-gtin-fallback-review`) Actor

Review supplied WooCommerce CSV identifiers for ID/SKU blocks on Global Unique ID fallback using a frozen native Woo 11.2 rule profile.

- **URL**: https://apify.com/remarkable_whipscorpion/woo-gtin-fallback-review.md
- **Developed by:** [Kagerou AP](https://apify.com/remarkable_whipscorpion) (community)
- **Categories:** E-commerce, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / useful identifier fallback review completed

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Woo GTIN Fallback Review

Review why an already mapped native WooCommerce update CSV may not fall back to Global Unique ID matching. This Actor compares your proposed CSV with a complete current export and reports the ID, SKU, and normalized GTIN evidence for each proposed row.

It uses an original small comparator based on a frozen native WooCommerce **11.2.0** source-rule profile (selected by input version `11.2`). It does not connect to your shop or write products. Prepare supplier column mapping before submitting the CSV.

### Try the original demo

Run with:

```json
{ "mode": "demo" }
```

The included fictional CC0 fixture contains two current products and four proposed rows:

| Proposed identifiers | Result |
| --- | --- |
| ID `999`, empty SKU, GTIN `00123` | `gtin_fallback_blocked` |
| Empty ID, SKU `OLD-SKU`, GTIN `00123` | `gtin_fallback_blocked` |
| Empty ID and SKU, GTIN `00123`, type `simple` | `gtin_match_eligible` |
| Empty ID and SKU, GTIN `00999`, type `variable` | `type_mismatch_review` |

Demo uses only this fixture. Supplying custom CSV data with `mode: "demo"` is rejected. There is no custom report event for demo; the platform start fee still applies.

### Review your CSV files

Use `mode: "review"`, supply `currentCsv` and `proposedCsv` as complete CSV **strings**, and set each acknowledgement to `true`:

- `rightsConfirmed`: you are authorized to upload and process both files in your Apify storage.
- `confirmUpdateExistingProducts`: the native importer will use **Update existing products**.
- `currentExportComplete`: the current export contains the complete target catalog. A partial export cannot establish that an ID, SKU, or GTIN is absent.
- `globalUniqueIdMappingConfirmed`: the declared column is mapped to native **Global Unique ID**.

The frozen profile accepts `nativeWooVersion: "11.2"` and binds it to the exact **11.2.0** tag and commit. Other versions are unsupported; this is not a support claim for every 11.2.x release. The Actor does not detect your installed WooCommerce version.

The default exact column name is `GTIN, UPC, EAN, or ISBN`. Because it contains commas, the CSV header must be quoted:

```csv
ID,SKU,Type,"GTIN, UPC, EAN, or ISBN"
11,PROJECT-A,simple,00123
12,PROJECT-B,simple,00999
```

`globalUniqueIdHeader` is fixed to this native header; custom overrides are rejected. Map supplier columns to these native names before running. The current export must include `ID`, `SKU`, `Type`, and the quoted Global Unique ID header. Missing current headers produce incomplete-coverage diagnostics. Duplicate headers and header whitespace aliases are rejected. Keep original identifier strings and leading zeros intact. Empty fields and absent columns are different evidence.

[sample-review-input.json](sample-review-input.json) uses the same fictional rows in **review mode**, includes the four acknowledgements, and is a charged custom-mode example when a useful report is delivered. Replace the two strings with your authorized native CSV data for a real review.

### How to read the report

The review records separate ID and SKU matches and preserves both original and parsed evidence. A truthy parsed ID or SKU blocks GTIN fallback; the Actor does not infer a generic ID-over-SKU update target. If ID and SKU identify different current rows, inspect `identifier_conflict_review`.

Integer ID strings use the native absolute-integer form within the supported 64-bit range: `0` and `000` parse to zero and do not block fallback; `-11` parses to `11`. Other PHP coercion forms and overflow remain unknown. An empty SKU or the single string `0` is false under native PHP truthiness and does not block fallback. Sanitation-sensitive SKU/GTIN text is unsupported rather than guessed.

With false parsed ID and SKU, a nonempty normalized GTIN can be eligible when exactly one current row matches and the parsed base type agrees. GTIN normalization retains ASCII digits, `X`, `x`, and hyphens, including leading zeros and case. The report preserves original and normalized GTIN strings. Duplicate normalized identifiers are ambiguous; no row is selected silently.

Type parsing removes `virtual` and `downloadable` flags, lowercases the remaining tokens, and uses the first native base type (`simple`, `variable`, `variation`, `grouped`, or `external`). A present blank Type cell or a flag-only Type defaults to `simple`. Quote composite CSV values such as `"simple, virtual"`. Absent proposed Type can produce `type_unknown_review`; unknown plugin types are unsupported.

ID matching uses the parsed absolute integer. SKU and normalized GTIN candidate evidence uses exact strings from the supplied export. Case-fold-only candidates make the relevant `SKUmatchKnown` or `GTINmatchKnown` evidence unknown; actual database collation is not simulated.

| Row status | Meaning |
| --- | --- |
| `gtin_fallback_blocked` | Supplied truthy ID or SKU has no exact current match while GTIN candidates exist; that identifier prevents fallback. |
| `id_sku_present_review` | Supplied truthy ID or SKU blocks fallback, with matched or unmatched evidence. Read match-known flags and the reason code; this does not establish import success. |
| `identifier_conflict_review` | ID and SKU match different current rows; no update target is promised. |
| `gtin_match_eligible` | Parsed ID and SKU are false, normalized GTIN uniquely matches, and parsed base type agrees. |
| `type_mismatch_review` | A unique GTIN candidate has a different parsed base product type. |
| `ambiguous` | Supplied identifier evidence or normalized GTIN has duplicate candidates. |
| `gtin_no_current_match` | Normalized GTIN has no candidate in the declared complete usable export. |
| `no_mapped_identifier` | Parsed ID/SKU are false and normalized GTIN is empty. |
| `variation_creation_unknown` | An unmatched proposed variation needs parent, order, or attribute checks outside this diagnostic. |
| `missing_current_coverage` | Current headers, identifiers, or the completeness acknowledgement do not support absence claims. |
| `collation_unknown` | GTIN case-fold candidates can change the result under database collation. |
| `type_unknown_review` | Proposed Type is absent, so no same-type claim is made. |
| `unsupported_version` / `unsupported_configuration` | Frozen version or required update/mapping configuration is unavailable. |
| `unsupported_identifier_format` / `unsupported_gtin_format` / `unsupported_product_type` | Native coercion, sanitation, GTIN mapping, or product type is outside the supported deterministic subset. |

`fallbackEligible` is a boolean or `null` when eligibility is unknown. Read row reason codes, candidate row numbers, and the unsupported/incomplete counts before using a result.

This diagnostic does not simulate the complete importer or promise that an update will succeed. Custom hooks, translated fields, site database collation, variation creation, parent ordering, attributes, product status, and other importer behavior remain outside its scope. It does not validate the check digit or commercial correctness of a GTIN, repair supplier mappings, or create an import-ready patch.

### Saved outputs

A completed report delivers:

- **REPORT.json** in the default key-value store: every proposed row, supplied ID/SKU, original and normalized GTIN, separate ID/SKU match references, GTIN candidate current-row references, eligibility, status/reason code, exact candidate counts, limits, frozen rule profile, and final billing. `currentIdentityEvidence` saves the complete current-row identity table once; use source-row references to inspect those identities.
- **REVIEW.csv** in the same store: every proposed row with original/parsed identifiers, GTIN strings, match row references, eligibility, declared Type, status/reason, and source version/hash. Spreadsheet formula cells are guarded; use REPORT.json for exact original evidence, parsed Type, match-known flags, exact candidate totals, and the complete current identity table.
- **OUTPUT**: final run summary, links, and billing state.
- One nonempty default Dataset summary containing `status`, `mode`, `totalRows`, `usefulRowCount`, `counts`, `ruleProfile`, and `billing`. Proposed records and the current identity table stay in REPORT.json rather than the Dataset summary.

The Dataset summary is saved before the custom report event, so its billing can remain `pending`. Read **OUTPUT** and **REPORT.json** for the final authoritative billing state. An unknown charge outcome stays unconfirmed; it is not silently retried. Actor Output links expose all these artifacts.

### Price and limits

The custom event `identifier_precedence_review_completed` costs **$0.05 per delivered useful identity review report**, at most one event per run. It is charged after the accessible complete report is saved. It is not a per-row fee.

The automatic platform event `apify-actor-start` is **$0.00005 per start event** at the configured 256 MiB memory, with the platform minimum of one event. The Actor does not manually charge this event. Allow **$0.05005** for one useful review including the start allocation. There is no default Dataset item charge.

Original demo, invalid input, and diagnostic-only/all-unknown reviews have **zero custom report events**. A report that includes at least one useful row and other unknown rows has one report event and visible coverage counts. Funded event capacity is checked before any useful Dataset, key-value-store, or checkpoint content is saved. Insufficient budget returns diagnostics instead of useful report details. Resuming a run does not intentionally duplicate its report fee.

Each CSV is limited to **5,000 data rows**, **5 MiB UTF-8**, and **200 columns**. CSV quoting is parsed with `csv-parse`; identifiers stay strings. The Actor accepts text only and does not fetch files or URLs. Both review outputs include every bounded proposed row (up to 5,000); proposed-row detail is not truncated. Each row's `IDmatches`, `SKUmatches`, and `GTINcandidateCurrentRows` reference arrays contain at most **50 references per field**. `IDmatchCount`, `SKUmatchCount`, and `GTINcandidateCount` retain exact totals; `candidatesTruncated` and `candidateDetailCap` expose this limit. Coverage also reports `candidateReferencesTruncatedRows`. The complete current identity evidence remains available once in REPORT.json, so a capped reference list is not a claim that no further candidates exist.

### Source and license

The source-rule profile is pinned to native WooCommerce **11.2.0**, commit `1699191d5074a22e7f6c43ff2da8fa9942905435`. The combined importer/abstract-importer SHA-256 is `13ccde0d3f978c6951e3b149d6eae4a00eccb8293ddb8bd5554b2e546604fbda`. The report's `ruleProfile` and [source-profile metadata](evidence/source-profile.json) preserve the same binding and hash method. Immutable upstream references are the [CSV importer](https://raw.githubusercontent.com/woocommerce/woocommerce/1699191d5074a22e7f6c43ff2da8fa9942905435/plugins/woocommerce/includes/import/class-wc-product-csv-importer.php) and [abstract importer](https://raw.githubusercontent.com/woocommerce/woocommerce/1699191d5074a22e7f6c43ff2da8fa9942905435/plugins/woocommerce/includes/import/abstract-wc-product-importer.php). See the [official native CSV importer documentation](https://woocommerce.com/document/product-csv-importer-exporter/) for the import workflow. This product is an independent diagnostic and is not affiliated with WooCommerce.

The comparator is original JavaScript; WooCommerce PHP importer code is not copied or executed. SDK `apify` is pinned to 3.7.2, and `csv-parse` is pinned to 7.0.2 in the shipping lockfile. The [CSV parser MIT notice](evidence/csv-parse-license.txt) is included; upstream software license notices remain with the dependencies.

The fictional fixture CSV values in this SKU are original project material dedicated under **CC0-1.0**. [LICENSE-FIXTURES.txt](LICENSE-FIXTURES.txt) describes the fixture-only dedication. This does not license uploaded customer data or upstream software.

# Actor input Schema

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

Demo runs only the included original fixture with no custom report event. CSV data supplied in demo is rejected. Review processes your CSV strings and may charge one useful report event.

## `currentCsv` (type: `string`):

Required in review: complete current native WooCommerce export text with ID, SKU, Type, and the exact declared Global Unique ID header. Maximum 5 MiB UTF-8, 5,000 data rows, and 200 columns. Omit in demo.

## `proposedCsv` (type: `string`):

Required in review: proposed native WooCommerce update CSV text. Perform supplier-to-native column mapping before using this Actor. Maximum 5 MiB UTF-8, 5,000 data rows, and 200 columns. Omit in demo.

## `nativeWooVersion` (type: `string`):

Input profile identifier 11.2 binds to the frozen native 11.2.0 tag/commit only; no claim for all 11.2.x releases. Other versions are unsupported. The Actor does not detect your installed version.

## `globalUniqueIdHeader` (type: `string`):

Frozen native header only: GTIN, UPC, EAN, or ISBN. This exact name contains commas, so quote it in CSV. Custom header overrides are rejected; map supplier columns before using the Actor.

## `confirmUpdateExistingProducts` (type: `boolean`):

Review requires true. Confirm that this review is for the native importer with Update existing products selected.

## `currentExportComplete` (type: `boolean`):

Review requires true. Confirm that the supplied current export is complete for the target catalog and includes identifier coverage; missing products cannot be inferred from an incomplete export.

## `globalUniqueIdMappingConfirmed` (type: `boolean`):

Review requires true. Confirm the declared GTIN/UPC/EAN/ISBN column is mapped to native Global Unique ID in the importer.

## `rightsConfirmed` (type: `boolean`):

Review requires true. Confirm permission to upload and process both CSV files in your Apify storage. This acknowledgement is exempt only for the included original demo.

## Actor input object example

```json
{
  "mode": "demo",
  "nativeWooVersion": "11.2",
  "globalUniqueIdHeader": "GTIN, UPC, EAN, or ISBN",
  "confirmUpdateExistingProducts": false,
  "currentExportComplete": false,
  "globalUniqueIdMappingConfirmed": false,
  "rightsConfirmed": false
}
```

# Actor output Schema

## `report` (type: `string`):

REPORT.json contains every proposed row, separate ID/SKU matches, original and normalized GTIN, candidate current rows, eligibility, status/reason, frozen profile, counts, limits, and final billing. Inspect unsupported and incomplete coverage before acting.

## `reviewCsv` (type: `string`):

REVIEW.csv contains the same row review facts with formula-guarded spreadsheet cells. It is a diagnostic review artifact, not an import-ready CSV.

## `output` (type: `string`):

OUTPUT contains run status, counts, profile, limits, saved report links, and final billing. Unknown charge outcomes remain unconfirmed.

## `summary` (type: `string`):

One summary is saved before the report event. Its billing can remain pending; OUTPUT and REPORT.json carry the final state.

# 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 = {
    "mode": "demo",
    "nativeWooVersion": "11.2",
    "globalUniqueIdHeader": "GTIN, UPC, EAN, or ISBN"
};

// Run the Actor and wait for it to finish
const run = await client.actor("remarkable_whipscorpion/woo-gtin-fallback-review").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 = {
    "mode": "demo",
    "nativeWooVersion": "11.2",
    "globalUniqueIdHeader": "GTIN, UPC, EAN, or ISBN",
}

# Run the Actor and wait for it to finish
run = client.actor("remarkable_whipscorpion/woo-gtin-fallback-review").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "mode": "demo",
  "nativeWooVersion": "11.2",
  "globalUniqueIdHeader": "GTIN, UPC, EAN, or ISBN"
}' |
apify call remarkable_whipscorpion/woo-gtin-fallback-review --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,remarkable_whipscorpion/woo-gtin-fallback-review"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/3TNfSFyw5o8GYsUSG/builds/mNaLQSJkP2kOb3Ol3/openapi.json
