Shopify rejects or silently merges product rows when the Handle column is wrong. Before importing, I run a small check that needs only the standard library.
What it checks
- empty handles
- handles that are not URL-safe (spaces, capitals, underscores)
- a handle that comes back after other products (variants must be contiguous)
- two rows with a title for the same handle
The script
import csv, re, sys
SLUG = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
def check(path):
problems = []
seen = {}
with open(path, newline="", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
last_handle = None
closed = set()
for line, row in enumerate(reader, start=2):
handle = (row.get("Handle") or "").strip()
title = (row.get("Title") or "").strip()
if not handle:
problems.append((line, "empty handle"))
continue
if not SLUG.match(handle):
problems.append((line, f"handle not URL-safe: {handle!r}"))
if handle != last_handle:
if handle in closed:
problems.append((line, f"handle {handle!r} reappears after other products"))
if last_handle is not None:
closed.add(last_handle)
last_handle = handle
if title:
if handle in seen and seen[handle] != line:
problems.append((line, f"second product row with title for handle {handle!r} (first at line {seen[handle]})"))
else:
seen[handle] = line
return problems
if __name__ == "__main__":
probs = check(sys.argv[1])
for line, msg in probs:
print(f"line {line}: {msg}")
print(f"{len(probs)} problem(s)")
sys.exit(1 if probs else 0)
Test run
With a small CSV containing one bad handle, one split product and one empty handle:
line 4: handle not URL-safe: 'Red Mug'
line 5: handle 'blue-mug' reappears after other products
line 5: second product row with title for handle 'blue-mug' (first at line 2)
line 7: empty handle
4 problem(s)
The exit code is 1 when problems are found, so you can use it in a script or CI step.
Notes
-
utf-8-sighandles the BOM that Excel adds. - Line numbers match the spreadsheet row, since the header is line 1.
- It does not check images, prices or SKUs; that is a separate check.
Free small scripts like this live in my repo: https://github.com/skeil1996-ui/python-automation-scripts-free
Top comments (0)