Catalog Merge Safety Auditor — SKU & GTIN Collision Graph
Pricing
from $8.00 / 1,000 catalog records
Catalog Merge Safety Auditor — SKU & GTIN Collision Graph
Audit multiple product catalogs before a supplier import or store migration. Find conflicting GTINs, reused SKUs, variant contradictions and unsafe proposed mappings, with exact evidence paths, affected records and HTML/CSV reports.
Pricing
from $8.00 / 1,000 catalog records
Rating
0.0
(0)
Developer
Ibrahim
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
15 days ago
Last modified
Categories
Share
Audit multiple product catalogs before a supplier import or store migration. Find conflicting GTINs, reused SKUs, variant contradictions and unsafe proposed mappings, with exact evidence paths, affected records and HTML/CSV reports.
The problem
A supplier calls a red medium shirt SKU SHIRT-01. Another feed reuses SHIRT-01 for a blue large shirt. An import joins on that SKU; a third record joins on a barcode. A simple duplicate-row check can miss the contradiction at the other end of this chain. This Actor builds the candidate identity graph and shows the source values and exact connecting path, so a catalog operator can stop a bad merge before importing.
Built for PIM teams, feed agencies, supplier onboarding, store migrations and catalog operations. This is a deterministic audit, not another product scraper and not an automatic catalog editor.
Quick start
Try the public synthetic fixture:
{"catalogs": [{"key": "store","scope": "demo-store","url": "https://commerce-actor-demos.vercel.app/merge-store.json"},{"key": "supplier","scope": "demo-store","url": "https://commerce-actor-demos.vercel.app/merge-supplier.csv"}],"proposedLinks": [{"from": {"catalog": "store","id": "shirt-red"},"to": {"catalog": "supplier","id": "mapped-blue"}},{"from": {"catalog": "store","id": "mug"},"to": {"catalog": "supplier","id": "mapped-case"}}],"maxRecords": 100}
The fixture contains deliberate errors. It should return 7 audited records, 2 collision components and 5 affected records, with complete source coverage. It is not real product inventory.
For private exports, supply inline records instead of a URL:
{"catalogs":[{"key":"shop","records":[{"id":"row-1","sku":"SHIRT-01","gtin":"4006381333931","brand":"Demo","color":"red","size":"M"}]}]}
Each catalog needs a unique key and exactly one of url or records. URL inputs accept RSS/Atom XML, quoted CSV/TSV, or JSON arrays/items/products wrappers. Flat column mappings work like "fieldMap":{"id":"supplier_id","sku":"seller_sku","gtin":"barcode","color":"colour"}.
How the graph works
- Preserve row identity as {catalog, id}. Missing ids become row-N for this source observation. Duplicate ids in the loaded source segment reject that source rather than guessing which row a mapping meant.
- Join records sharing an exact, checksum-valid string GTIN. GTIN-8/12/13/14 values are zero-padded to 14 digits for comparison. Numeric, malformed and all-zero barcodes are excluded and reported. A valid checksum does not certify GS1 allocation or ownership.
- Join exact, case-sensitive SKUs within one scope. The default scope is the catalog key, so matching SKU text from different suppliers does not join by accident. Set the same explicit scope only when the catalogs truly use the same SKU namespace.
- Apply your proposedLinks as hypothetical identity connections. References use the source key and string record id. Unknown references are reported and make the simulation partial.
- Find conflicting valid GTINs, brand, color, size and positive integer multipack quantity within each connected component. Case and whitespace normalize for attributes. Missing values stay unknown; no translation or semantic synonym guessing is performed.
- Return every loaded row with its component, issue codes, source position, coverage and review state. REPORT contains witnesses and a bounded spanning forest with exact evidence paths, plus affected-record counts. These paths explain connections; they are not claimed to be the shortest paths in the original graph.
Titles, shared photos, price differences, stock changes and manufacturer part numbers do not create identity links. Prices/stock can legitimately differ between sellers. Product groups, bundles, languages, aliases and retailer-specific variant names can need manual review. no_detected_conflict means no supported contradiction among loaded records; it is not permission to merge or a certification of product identity.
Output
The Dataset has one row per audited source record, not per issue. Main fields: catalog, id, sku, gtin, componentId, componentSize, status, issueCodes, dataIssues, sourceUrl, rowNumber, coverageStatus and requiresReview. Status is collision_review, no_detected_conflict or insufficient_identifiers.
Run storage:
- REPORT: full JSON report, graph spanning forest, component witnesses, proposed-link outcomes, source coverage and delivery counts.
- REPORT.html: readable collision report with evidence chains and partial-coverage warnings.
- AUDIT.csv: delivered audit rows with formula-leading cells neutralized for spreadsheets.
- RUN_STATS: loaded/delivered counts, failed sources, limits and budget status.
- MERGE_PACKET: prepared input-fingerprinted audit used for restart recovery. Dataset identities are recovered before retrying, avoiding repeat delivery/charging in the same run/storage.
Verified cloud output
[{"catalog": "store","id": "shirt-red","sku": "SHIRT01","gtin": "04006381333931","componentSize": 3,"status": "collision_review","issueCodes": ["MULTIPLE_GTINS_IN_IDENTITY","CONFLICTING_COLOR","CONFLICTING_SIZE"],"coverageStatus": "complete"},{"catalog": "store","id": "mug","sku": "MUG1","gtin": "01234567890128","componentSize": 2,"status": "collision_review","issueCodes": ["MULTIPLE_GTINS_IN_IDENTITY","CONFLICTING_PACK_QUANTITY"],"coverageStatus": "complete"},{"catalog": "store","id": "clean","sku": "CLEAN","gtin": "01234567890135","componentSize": 1,"status": "no_detected_conflict","issueCodes": [],"coverageStatus": "complete"},{"catalog": "supplier","id": "wrong-sku","sku": "SHIRT01","gtin": "05901234123457","componentSize": 3,"status": "collision_review","issueCodes": ["MULTIPLE_GTINS_IN_IDENTITY","CONFLICTING_COLOR","CONFLICTING_SIZE"],"coverageStatus": "complete"},{"catalog": "supplier","id": "mapped-blue","sku": "SHIRT-BLUE","gtin": "05901234123457","componentSize": 3,"status": "collision_review","issueCodes": ["MULTIPLE_GTINS_IN_IDENTITY","CONFLICTING_COLOR","CONFLICTING_SIZE"],"coverageStatus": "complete"},{"catalog": "supplier","id": "mapped-case","sku": "CASE6","gtin": "01234567890142","componentSize": 2,"status": "collision_review","issueCodes": ["MULTIPLE_GTINS_IN_IDENTITY","CONFLICTING_PACK_QUANTITY"],"coverageStatus": "complete"},{"catalog": "supplier","id": "unknown","sku": "","gtin": null,"componentSize": 1,"status": "insufficient_identifiers","issueCodes": [],"coverageStatus": "complete"}]
Pricing
Launch price: $8 per 1,000 audited source records ($0.008 each), plus the $0.00005 memory-based Actor-start event, minimum one event. Platform usage is included after pay-per-event activation. One record with several findings is still one charged dataset row. Clean, insufficient-identifier and collision rows are all completed audits. Failed source diagnostics and report artifacts are not separately charged. Check the live Pricing tab; it is authoritative.
A 100-record run is at most $0.80 in record events plus startup. The default $1 run budget may lower the loaded-record cap. Scope-dependent graph analysis uses the records actually loaded within that cap; any skipped rows/sources are plainly partial. Increase both maxRecords and the run charge limit for a full export audit. Never interpret a partial audit as whole-catalog clearance.
Limits and access
1–10 sources; 20,000 total loaded records; 20,000 proposed links; 8 MB input and each decompressed feed; 20-second HTTP requests; five same-origin guarded redirects. Shared per-host pacing and robots.txt checks apply. No login, credentials, private-network fetch, anti-bot evasion, browser rendering, LLM or external paid API is required. Output fields are bounded; component member display caps at 100 and a witness path display at 1,000 edges, with truncation flags. Full forest edges remain in REPORT. Export formats are public HTTP feeds or customer-provided inline data. No shop/PIM writes or notifications are sent.
Use a new run for new input; restart recovery requires identical input/build/default storage. A partial source failure retains useful records but forbids whole-source clearance. All-source failure fails after saving diagnostics. Catalog corrections and merge decisions remain yours.
API example
curl -X POST 'https://api.apify.com/v2/acts/skyfishdev~catalog-merge-safety-auditor/run-sync-get-dataset-items' \-H 'Authorization: Bearer YOUR_APIFY_TOKEN' \-H 'Content-Type: application/json' \--data-binary @input.json
Save input.json using the example above. Use asynchronous runs for large audits; read REPORT and RUN_STATS even when exporting just the Dataset. Schedule the same saved Task to check a recurring supplier feed; this Actor does not retain or compare historical catalogs between separate runs.
Local development
npm cinpm test
Put authorized input in storage/key_value_stores/default/INPUT.json and run npm start. Networking, graph tests, spending-limit tests and restart recovery are included.
Identifier context: GS1 variants and GTINs. This Actor is not affiliated with GS1 and cannot validate manufacturer ownership. No uniqueness or revenue guarantee is made.