Importing Metafields

The Metafields import writes custom metafield values into your Shopify store from a CSV/Excel file, a Google Sheet, or directly from another connected store. It is a dedicated metafields sheet — one metafield per row — so a single file can set values on many different kinds of records at once: products, variants, collections, customers, orders, pages, companies, company locations, metaobjects, articles, and the shop itself.

Under the hood every row is applied with Shopify's metafieldsSet mutation. That mutation is an upsert keyed on owner + namespace + key, so running the same file twice updates the same metafields instead of creating duplicates, and a row with a blank value deletes the metafield.

For the wizard itself — uploading, mapping, dry runs, schedules — see Importing into EcomSolo.

Metafield values vs. definitions

This import writes metafield values — the data stored on each record. It does not create or manage metafield definitions (the schema under Settings → Custom data that gives a metafield its name, type and validation). This mirrors how Matrixify works: values are imported, definitions are set up separately.

You can import values with or without a matching definition:

  • No definition: the value is still stored on the record (Shopify accepts it through the API), and it appears in EcomSolo's Metafields dashboard and via the Shopify API — but it will not show in the product/customer editor in Shopify Admin, which only renders metafields that have a definition.
  • A definition exists: the row's Type must match the definition's type, and the value must pass the definition's validation, or the row fails.

So for a value to be both stored and visible/editable in Shopify Admin, create the definition first in Shopify Admin → Settings → Custom data, then import the values against it.

Importing or exporting the definitions themselves is not supported yet — and neither Matrixify does it. Create your definitions in Shopify Admin. (Definition import/export is planned as a separate feature.)

Columns

ColumnRequiredNotes
OwneryesThe kind of record this metafield attaches to. One of product, variant, collection, customer, order, page, company, companylocation, metaobject, article, shop. (For shop there is only one owner, so no id/handle is needed.)
Owner IDone of ID / HandleThe owner's Shopify ID — either a full GID (gid://shopify/Product/123) or a bare numeric id (123).
Owner Handleone of ID / HandleThe owner's natural key instead of an id (see the table below). Use whichever you have; Owner ID wins if both are present.
NamespaceyesThe metafield namespace, e.g. custom or my_fields.
KeyyesThe metafield key within the namespace, e.g. care_instructions.
TypeyesThe Shopify metafield type — must match the definition (see Types).
Valuesee noteThe value, written according to its type. Leave blank to delete the metafield.

Common export headers map automatically: Owner Type / Object → Owner, ID → Owner ID, Handle → Owner Handle, Metafield Namespace → Namespace, Metafield Key → Key, Metafield Type → Type, Metafield Value → Value.

Owner Handle conventions

When you use Owner Handle instead of an id, the natural key depends on the owner type:

OwnerOwner Handle is…Example
productthe product handleblue-cotton-tee
variantproduct_handle.variant_titleblue-cotton-tee.Large / Blue
collectionthe collection handlesummer-sale
customerthe customer emailsam@example.com
orderthe order name (with #)#1234
pagethe page handleabout-us
companythe company nameAcme Wholesale
companylocationthe company location nameAcme — Berlin
articleblog_handle.article_handlenews.spring-launch
metaobjectdefinition_handle.entry_handleauthors.jane-doe
shop(none — leave blank)

Types

The Type must be a valid Shopify metafield type and must match the definition. Values are written to match the type; the grammar per family is below.

Text

  • single_line_text_field, multi_line_text_field — plain text. Write the text as-is.

Numbers

  • number_integer — a whole number, e.g. 42.
  • number_decimal — a decimal, e.g. 19.99.

Boolean

  • booleanTRUE/FALSE, yes/no, or 1/0 (case-insensitive).

Dates, colors, URLs

  • color — a hex color, e.g. #1a2b3c.
  • url — an absolute URL.
  • dateYYYY-MM-DD, e.g. 2026-07-09.
  • date_time — ISO 8601, e.g. 2026-07-09T14:30:00Z.

JSON

  • json — a valid JSON string, e.g. {"tier":"gold","points":120}.

Measurements and money

Each of these accepts a human-readable string or the equivalent JSON object:

  • money"15.00 EUR" or {"amount":"15.00","currency_code":"EUR"}.
  • weight"2.5 kg" or {"value":2.5,"unit":"kg"} (units: kg, g, oz, lb).
  • volume"1.5 l" or {"value":1.5,"unit":"l"} (units: ml, cl, l, m3, …).
  • dimension"30 cm" or {"value":30,"unit":"cm"} (units: mm, cm, m, in, ft, yd).

The shorthand form ("2.5 kg") passes its unit token straight through; Shopify accepts these lowercase codes and normalises them on save (e.g. kg is stored and returned as KILOGRAMS).

Rating

  • rating — JSON {"value":4.5,"scale_min":1,"scale_max":5}. The scale comes from the definition; the value must sit within it.
  • link — a bare URL, or JSON {"text":"Read more","url":"https://…"}.

Rich text

  • rich_text_field — plain text is wrapped as a single paragraph. If you already have Shopify's rich-text JSON, it passes through unchanged. Limitation: HTML and Markdown are not deep-converted into rich-text structure — headings, lists, links and bold/italic markup are treated as literal text. For structured rich text, supply Shopify's rich-text JSON.

References

The reference types point at another record. Give the target's natural key (the same conventions as Owner Handle) or a full gid://…:

TypeValue is the target's…
product_referenceproduct handle or gid
variant_referenceproduct_handle.variant_title or gid
collection_referencecollection handle or gid
customer_referencecustomer email or gid
order_referenceorder name (#1234) or gid
page_referencepage handle or gid
company_referencecompany name or gid
metaobject_referencedefinition_handle.entry_handle or gid
article_referenceblog_handle.article_handle or gid
file_referencethe file's handle/URL or gid

Lists

Any type can be a list by prefixing list. — e.g. list.single_line_text_field, list.number_integer, list.product_reference. Separate the values with a comma, semicolon, or newline, or supply a JSON array:

Blue;Green;Red
["Blue","Green","Red"]

List reference types work the same way — a list of handles/emails/names (or gids), separated or as a JSON array.

How metafields are matched

Every row is matched on owner + namespace + key:

  • If that metafield already exists on the owner, its value is updated.
  • If it doesn't exist, it is created.
  • If the Value is blank, the metafield is deleted (matching the behaviour of Matrixify-style sheets).

Because metafieldsSet is an upsert, the whole import is idempotent — re-running the same file produces the same end state.

Operations

Step 1 of the wizard picks what the file does:

  • Create — new metafields only; a row whose metafield already exists on the owner fails.
  • Update — existing metafields only; a row that doesn't yet exist fails.
  • Upsert (the default) — creates or updates as needed, and a blank Value deletes.
  • Delete — permission-gated; rows carry the identity columns only (Owner + Namespace + Key) and the metafield is removed. A metafield that isn't there is skipped, so re-running the same delete file is safe.

Deleting a metafield removes that one value from the record; it never touches the metafield definition. There's no undo, but you can re-import the value at any time.

Large sheets import fast. Rows are dispatched to Shopify in batches (up to 25 metafields per call), so a sheet with thousands of rows imports far quicker than one row at a time — with no change to the columns or behaviour above.

Importing from another store

On the wizard's Source step, pick From another store to copy metafields from a connected store — no file needed. Owner, namespace, key, type and value come across, matched by owner + namespace + key. Combined with a schedule this becomes a recurring one-way metafield sync.

Results and freshness

Metafields you create, update or delete take effect in Shopify immediately, and EcomSolo's dashboards refresh within seconds of the run.

Sample file

A ready-to-run sample lives at features/importing/examples/metafields-sample.csv — text, number, boolean, JSON, money, weight, date, URL, a list, references, an owner-by-GID row, a blank-value delete row, and both product and customer owners:

Owner,Owner ID,Owner Handle,Namespace,Key,Type,Value
product,,blue-cotton-tee,custom,care_instructions,single_line_text_field,Machine wash cold
product,,blue-cotton-tee,custom,warranty_years,number_integer,2
product,,blue-cotton-tee,custom,is_bestseller,boolean,TRUE
customer,,sam@example.com,loyalty,profile,json,"{""tier"":""gold"",""points"":120}"
order,,#1234,custom,gift_wrap_fee,money,5.00 EUR

Dry run shows the create/update/delete split before anything is written.

Troubleshooting

Error in the reportWhat it means / what to do
row requires an OwnerEvery row needs an owner type.
could not resolve ownerThe Owner ID / Owner Handle didn't match a record — check the handle convention for that owner type.
type does not match the metafield definitionA definition already exists for that owner + namespace + key with a different type. Match the Type column to the definition (or change the definition) in Settings → Custom data, then re-run.
Value imported but not visible in Shopify AdminThe value saved fine, but there's no definition, so Shopify Admin's product/customer editor doesn't render it. Create a definition in Settings → Custom data (or view it in EcomSolo's Metafields dashboard / the API).
invalid value for type <type>The value doesn't parse for that type (bad JSON, wrong date format, unit not recognised, etc.).

FAQ

Will re-importing create duplicates? No — rows match on owner + namespace + key and metafieldsSet upserts, so re-runs update in place.

How do I delete a metafield? Leave the Value blank on its row. The metafield is removed.

Do I have to create definitions first? No — values import with or without a definition. But without one the metafield won't appear in Shopify Admin's editor (it's still there via the API and EcomSolo's dashboard), and there's no type validation. Create the definition in Settings → Custom data for full visibility and validation. This import never creates definitions — same as Matrixify.

Can I import the metafield definitions themselves? Not yet — this import handles values only (as does Matrixify). Create definitions in Shopify Admin; definition import/export is planned separately.

Can one file target different owners? Yes — that's the point of the dedicated metafields sheet. Mix products, customers, orders and more in the same file; the Owner column on each row decides where it lands.