Feedguard - Inventory Sync
What FeedGuard does
FeedGuard keeps your Shopify products in sync with your suppliers. It collects stock, prices and product data from wherever your supplier puts it — a CSV, an Excel file, an FTP folder, a Google Sheet, an S3 bucket or a REST API — transforms it to match your store, and writes it to Shopify on a schedule you choose.
What makes it different from a plain importer:
- You see every change before it happens. Each run compares the feed against your live catalogue and shows exactly which products would change, from what value to what value.
- It refuses unsafe syncs. Circuit breakers stop a run if a supplier file would change too much of your catalogue, zero out too many products, or has suddenly lost most of its rows.
- Anything can be undone. Every applied change is stored with its previous value, so a whole run can be reverted with one click.
Quick start
- Create a feed. Go to Feeds → Create feed, give it a name (for example “Acme daily stock”) and choose the source type. Each source type shows a short setup guide right in the form.
- Fetch the file once. Open the feed and press Test fetch (for upload feeds, drop your file in and press Upload first). FeedGuard needs one file before it can read your column names.
- Map the columns. Press Edit column mapping, then Auto-map columns. Check the result, adjust anything you like, and press Save mapping. The only required mapping is SKU — it is how feed rows are matched to your products.
- Run it as a dry run. Press Run now and open the run. Nothing has been written to your store yet; the change list shows what a live sync would do.
- Go live and schedule it. After three clean runs, press Enable live mode in the Sync mode card, then choose a schedule. From then on the feed runs by itself.
No supplier file yet?
Download the sample feed from feedguard.synovaapps.com/sample-feed.csv and use it with a CSV/Excel upload feed. It contains 15 example products with SKUs, prices, stock levels and weights, so you can walk through the whole process before touching real data.
The safest way to start
If you are moving over from another app, leave FeedGuard in dry-run mode and keep your current app running. The change list tells you whether FeedGuard's mapping produces the same result. When the two agree, switch the old app off and turn live mode on.
Choosing a source type
A feed has exactly one source. If a supplier sends you two different files, create two feeds.
| Source type | Use it when |
|---|---|
| CSV/Excel upload | You receive files by email or download them manually. |
| URL fetch (HTTP/HTTPS) | The supplier gives you a permanent download link. |
| FTP / FTPS | The supplier drops files on an FTP server. |
| SFTP | Same, but over SSH (port 22). |
| Google Sheets | Stock is maintained in a spreadsheet, by you or the supplier. |
| Amazon S3 or compatible | Files land in an S3, MinIO or Cloudflare R2 bucket. |
| REST API (JSON) | The supplier has an API instead of files. |
You can change a source's settings at any time from the feed page: Source → Edit source settings. Passwords and keys are never shown again — leave those fields blank to keep the saved values, or type a new value to replace them.
CSV / Excel upload
- Create the feed with source type CSV/Excel upload.
- On the feed page, drag your file onto the upload box (or press Add file) and press Upload.
- Press Run now whenever you upload a new version of the file.
Accepted: .csv, .tsv, .txt, .xlsx, .xml, .json and .zip. A zip containing several files with identical columns is merged into one dataset; files with different columns are skipped and reported in the run's warnings.
URL fetch (HTTP/HTTPS)
| Field | What to enter |
|---|---|
| Feed URL | The direct link to the file. Opening it in a browser should download the file, not show a login page. |
| Extra headers (JSON) | Optional. For API keys, e.g. { "X-Api-Key": "abc123" }. |
| Basic auth user / password | Optional. Use these if the link is protected by a username and password. |
Scheduled runs are skipped automatically when the file has not changed since the last run, so pointing at a large file that only updates daily costs nothing in between.
FTP and FTPS
| Field | What to enter |
|---|---|
| Host | For example ftp.supplier.com — no ftp:// prefix needed. |
| Port | Leave blank for 21. |
| User / Password | The credentials your supplier gave you. |
| Directory | The folder the files land in, e.g. /export. Leave blank for the root folder. |
| File pattern | Which files to take, e.g. *.csv or stock_*.xlsx. Leave blank to take everything. |
| Use FTPS | Tick only if your supplier requires explicit TLS. |
The newest matching file is used. Press Test fetch to confirm the connection before scheduling anything.
SFTP
Identical to FTP, except it runs over SSH (usually port 22) and you may authenticate with a private key instead of a password. Paste the whole key including the -----BEGIN …----- and -----END …----- lines into the Private key field, and leave the password blank.
Google Sheets
Find the spreadsheet ID in the sheet's URL — it is the long code between /d/ and /edit:
https://docs.google.com/spreadsheets/d/1AbC...XyZ/edit#gid=0
^^^^^^^^^^ this is the ID
Option A — public sheet (no credentials)
- In the sheet, press Share and set general access to Anyone with the link → Viewer.
- In FeedGuard, enter the spreadsheet ID and the tab name (for example
Sheet1). Leave the service account field empty.
Option B — private sheet (service account)
Use this when the sheet must stay restricted. It takes about five minutes, once.
- Open console.cloud.google.com and create a project (any name).
- Go to APIs & Services → Library, search for Google Sheets API and press Enable. Do not skip this step.
- Go to APIs & Services → Credentials → Create credentials → Service account. Give it a name and finish; no roles are needed.
- Open the new service account, go to the Keys tab and choose Add key → Create new key → JSON. A file downloads.
- Open the JSON file and copy the
client_emailvalue. In your Google Sheet, press Share and give that address Viewer access. - In FeedGuard, paste the entire contents of the JSON file into Service account key (JSON) and save.
The sheet can now stay private to everyone else. FeedGuard reads it through Google's API.
Amazon S3 and compatible storage
| Field | What to enter |
|---|---|
| Bucket | The bucket name only, without s3://. |
| Region | For example eu-central-1. Leave blank for us-east-1. |
| Key prefix | Optional folder path, e.g. feeds/. |
| Access key ID / Secret access key | Credentials with read access to the bucket. |
| Custom endpoint | Only for MinIO or Cloudflare R2. Leave blank for AWS. |
| File pattern | For example *.csv. |
REST API (JSON)
| Field | What to enter |
|---|---|
| API URL | The endpoint that returns your products as JSON. |
| Headers (JSON) | Authentication, e.g. { "Authorization": "Bearer abc123" }. |
| Records path | Where the product array sits in the response, in dot notation — e.g. products or data.items. Leave blank if the response is already an array. |
| Pagination | None, Page number or Offset. |
| Page/offset parameter | The query parameter the API expects, e.g. page or skip. |
| Page size parameter / Page size | For example limit and 250. |
| Max pages | A safety limit on how many pages one run will fetch. |
Nested JSON objects are flattened into dotted column names, so { "meta": { "barcode": "…" } } becomes a column called meta.barcode that you can map like any other.
Formats FeedGuard reads
| Format | Notes |
|---|---|
| CSV / TSV / TXT | The separator is detected automatically — comma, semicolon, tab or pipe. Quoted fields and byte-order marks are handled. European decimal commas (10,50) are understood in numeric fields. |
| Excel (.xlsx) | The first worksheet is used. Formula cells are read as their calculated value. |
| JSON | Either an array of records, or an object containing one (see Records path). Nested objects become dotted columns. |
| XML | The repeating record list is detected automatically. |
| ZIP | Unpacked automatically. Several files with the same columns are merged; others are skipped and listed in the run warnings. |
What makes a good feed file
- A header row with column names in the first row.
- A SKU column whose values match your Shopify variant SKUs exactly (upper/lower case does not matter).
- One row per variant, not per product.
Empty header cells are renamed automatically (column_3), duplicates get a numeric suffix, and both are reported in the run's warnings so nothing changes silently.
How matching works
Every feed row must identify a product in your store. That is the match key, chosen when you create the feed:
- Variant SKU — the default and the most reliable.
- Barcode — use when the supplier only sends EANs or UPCs.
- Handle — for product-level matching.
Rows whose key is not found in your store are counted as Not found and listed on the run page. They are never guessed at.
Auto-map
On the mapping page, press Auto-map columns. FeedGuard reads your file's headers and matches them to Shopify fields, including common non-English names:
| Shopify field | Headers recognised |
|---|---|
| SKU | sku, item no, item code, part number, artikel, product code, model |
| Inventory quantity | qty, quantity, stock, inventory, available, on hand, lager, lagerbestand |
| Price | price, unit price, net price, selling price, preis |
| Compare-at price | compare, msrp, rrp, uvp, list price, retail |
| Cost per item | cost, wholesale, purchase price, einkauf |
| Barcode | barcode, ean, upc, gtin, isbn |
| Title | title, name, product name, bezeichnung |
| Tags | tags, category, categories, group |
| Weight | weight, gewicht |
| Status | status, active |
| Image URL | image, img, photo, picture, thumbnail, thumb |
Auto-map is a starting point, not a decision — review every row before saving. Remove any mapping you do not want written.
Templates
Three one-click starting points sit above the mapping list:
- Stock & price sync — SKU, quantity with a stock buffer of 3, and price. The classic supplier feed.
- Price with markup — SKU plus price calculated as supplier price × 1.4, rounded to
.99, with the supplier price also stored as cost. Adjust the multiplier to your margin. - Full catalogue update — every field FeedGuard can recognise in your file.
Fields you can write to
| Field | Notes |
|---|---|
| Inventory quantity | Written at the feed's chosen location. Inventory tracking is switched on automatically if it was off. |
| Price | Plain number. Currency symbols and thousands separators should be removed with a transform if the supplier includes them. |
| Compare-at price | Leave the source cell empty to clear it. |
| Cost per item | Stored on the inventory item; never shown to customers. |
| Title | Product title. Use with care if you write your own product names. |
| Tags | Comma-separated. Comparison ignores order, so re-ordered tags do not count as a change. |
| Weight | Numeric value; the variant's existing unit (kg, g, lb, oz) is kept. |
| Status | Supplier wording is understood — see Product status below. |
| Barcode | EAN, UPC or GTIN. |
| Image URL | Added when the product has no image yet; existing images are never touched. |
Product status
Suppliers rarely write “active” or “draft”, so common availability wording is translated for you:
- Becomes active: active, published, enabled, visible, in stock, low stock, available, true, 1
- Becomes draft: draft, inactive, disabled, hidden, out of stock, unavailable, discontinued, false, 0
- Ignored: anything unrecognised. The row's other fields still sync — only the status is skipped, so no wrong value is ever written.
The preview
Below the mapping you see the first rows exactly as they will be written, after transforms and filters, plus a count of how many rows pass your filters. Save the mapping to refresh it. If a value looks wrong here, it will be wrong in your store — fix it before running.
How transforms work
Each mapping can carry a chain of transform steps, applied top to bottom. Press + Step on a mapping row to add one. The output of each step feeds the next, so order matters: multiply first, then round.
| Step | Setting | What it does |
|---|---|---|
| Trim whitespace | — | Removes leading and trailing spaces. |
| UPPERCASE / lowercase | — | Changes the case of the whole value. |
| Add prefix | Text | ACME- turns 1234 into ACME-1234. |
| Add suffix | Text | Appends text to the end of the value. |
| Find & replace | Find / Replace with | Replaces every occurrence. Case-sensitive. |
| Regex replace | Pattern / Replace with | For advanced cleanups, e.g. pattern [^0-9.] with an empty replacement strips everything except digits and dots. |
| Math | Expression | x is the incoming value. Supports + - * / and brackets: x * 1.4, (x + 2) * 1.2. |
| Round | Mode | 2dp → two decimals · integer → whole number · .99 → rounds up to the next .99 ending. |
| Stock buffer | Min qty | Any quantity below the minimum becomes 0. Set 3 to stop selling your supplier's last two units. |
| Default if empty | Value | Used only when the source cell is blank. |
| Lookup table | Table name | Replaces the value using a CSV you uploaded — see Lookup tables. |
Recipes
| Goal | Steps |
|---|---|
| Sell at 40% margin over supplier price | Math x * 1.4 |
| …and end every price in .99 | Math x * 1.4 → Round .99 |
| Never sell the last 3 units | Stock buffer 3 |
| Supplier sends prices as “€ 12,50” | Regex replace [^0-9,.] with nothing → Find & replace , with . |
| Blank stock should mean zero | Default if empty 0 |
| Your SKUs are prefixed, the supplier's are not | Add prefix ACME- |
| Convert grams to kilograms | Math x / 1000 |
| Translate supplier status codes | Lookup table, or Find & replace per value |
If a step cannot be applied — for example Math on a value like n/a — the row is reported as a transform error on the run page and that field is left untouched. The rest of the run continues.
Row filters
Filters decide which rows of the file are processed at all. Add them below the mappings. Each filter is either:
- Keep only if — the row must match, or it is ignored.
- Skip row if — the row is ignored when it matches.
Available conditions: equals · does not equal · contains · does not contain · is greater than · is less than · is empty · is not empty.
Useful filters
| Goal | Filter |
|---|---|
| Ignore rows without a SKU | Keep only if sku is not empty |
| Skip discontinued products | Skip row if status contains discontinued |
| Only sync one brand from a multi-brand file | Keep only if brand equals Velocity |
| Ignore items below a minimum price | Skip row if price is less than 5 |
Filtered rows are counted on the run page as Filtered out, so you can always see how many rows a filter removed.
Lookup tables
A lookup table is a two-column CSV of replacements you can reuse in any feed — handy for supplier codes, brand names or unit labels.
- Prepare a CSV with a header row and two columns: the value to find, and the replacement. For example:
from,to AVL,active EOL,draft B-Ware,refurbished - Go to Settings → Manage lookup tables, give the table a name (for example
status-codes), upload the file and save. - On any mapping, add a Lookup table step and type that table name.
Values that are not in the table pass through unchanged. Uploading a table with the same name replaces it, and every feed using it picks up the new version on the next run.
Starting a run
- Test fetch — collects the file and stores it, without mapping or writing. Use it to check credentials.
- Run now — the full pipeline. Manual runs always process the file, even if it has not changed.
- Scheduled runs — happen automatically, and are skipped when the source file is unchanged.
What happens during a run
The progress bar on the feed page shows the real stage and counts:
- Fetching from source
- Parsing file
- Applying mapping & filters
- Reading store catalogue — the longest stage on large stores; shown page by page
- Computing diff
- Applying changes — only in live mode, with a running count
- Creating products — only when product creation is enabled
Reading the run page
| Tile | Meaning |
|---|---|
| Rows in file | How many data rows the file contained. |
| Filtered out | Rows removed by your row filters. |
| Matched in store | Rows whose match key was found in your catalogue. |
| Not found | Rows with no matching product. Sample SKUs are listed below the tiles. |
| Items changing | Products with at least one differing value. |
| Going to zero | Products whose stock would drop to zero. Watch this one. |
Run statuses
| Status | Meaning |
|---|---|
| Success | The run completed. In dry-run mode that means the report is ready; in live mode, that changes were written. |
| Warning | Completed, but something needs a look — transform errors, or some changes rejected by Shopify. |
| Skipped | The source file was unchanged since the last run. Normal for scheduled feeds. |
| Failed | Nothing was written. Either the source could not be read, or a guardrail stopped the run. The reason is shown at the top of the page. |
The change log
Every difference is recorded as one line: SKU, field, before value, after value, and whether it was applied. Failed writes show the exact reason from Shopify. Use Download change log for the complete list as CSV — useful for auditing, or for sending to a supplier when their data is wrong.
Change logs are capped at 5,000 lines per run to keep pages fast; the run stats say when a log was truncated.
Why guardrails exist
Supplier files fail in predictable ways: an export gets truncated, a column shifts, a decimal point moves. Guardrails compare the shape of the change against limits you set, and stop the run before anything is written — even in live mode.
The four circuit breakers
| Breaker | Default | Catches |
|---|---|---|
| Maximum share of catalogue changing | 30% | The wrong file, or a shifted column rewriting everything. |
| Maximum share going to zero stock | 20% | A truncated or empty stock column emptying your store. |
| Maximum file shrinkage vs last run | 50% | Partial or failed supplier exports. |
| Price floor and ceiling | Off | Decimal-point mistakes and mis-keyed supplier prices. |
Find them in the Guardrails card on the feed page. Adjust the percentages to your catalogue, set price bounds if your range is predictable, and press Save guardrails.
When a guardrail trips
- The run stops with status Failed and states the reason, for example: “File row count dropped 73% vs last run (4 vs 15) — limit is 50%.”
- Nothing is written to your store.
- An alert email goes out if you have a Guardrail tripped or Run failed alert configured.
- The run page still lists every change that would have been made, so you can judge whether the file is broken or the change is genuine.
What to do next
- The file is wrong — ask the supplier for a fresh export. Nothing to undo, because nothing happened.
- The change is genuine — for example a real seasonal clear-out — raise the relevant limit temporarily, run again, then set it back.
Guardrails evaluate independently on every run, so nothing gets stuck: fix the cause and the next run proceeds normally.
Dry run is the default
Every new feed starts in dry-run mode. Runs fetch, parse, map and compare — then report. Nothing is written to Shopify. Use dry runs freely while you tune mappings and transforms.
Enabling live mode
The Enable live mode button in the Sync mode card unlocks after three clean runs on that feed. This is deliberate: it guarantees you have seen three diffs before the app is allowed to write anything. The feed header always shows which mode it is in — a red Live mode badge or a blue Dry run badge.
You can switch back to dry run at any time; the button is right there.
Reverting a run
Open any run that applied changes and press Revert this run. FeedGuard writes every changed field back to the value it held before that run, and records the rollback as its own run with a full change log — so your audit trail stays complete.
What revert does and does not restore
- Restored: prices, compare-at prices, cost, inventory quantities, titles, tags, weights, barcodes and statuses.
- Not restored: products that were created (they remain, as drafts) and images that were added (they remain). Both are reported as skipped in the rollback stats.
- Skipped: products that no longer exist in your store, listed by SKU.
Revert restores what was, not what the feed says. If you revert and then run the feed again, the feed's values are applied once more — the two actions are independent.
Setting a schedule
Open the feed, choose an option in the Schedule card and press Save schedule. The next run time is shown underneath, and saving a schedule also activates the feed.
| Option | Available on |
|---|---|
| Manual only | All plans |
| Daily (02:00) | All plans |
| Every 6 hours | All plans |
| Every hour | Growth and Pro |
| Every 15 minutes | Pro |
Options above your plan's frequency are shown but disabled, labelled “upgrade required”.
How often should a feed run?
- Your supplier updates once a day — daily is enough. More frequent runs are simply skipped as unchanged.
- Stock moves during the day — hourly.
- Dropshipping fast-moving products — every 15 minutes, combined with a stock buffer so you never sell your supplier's last unit.
Unchanged files are skipped
FeedGuard fingerprints every fetched file. If a scheduled run finds the same file as last time, it stops early and records a Skipped run — no catalogue read, no API calls, no noise. Manual runs always process, and saving a new mapping clears the fingerprint so your changes take effect on the next scheduled run too.
Failures and retries
Runs that fail because of a network or source problem are retried automatically with increasing delays before being reported. Guardrail failures are not retried — they are a decision, not an error.
Pausing
Press Pause feed to stop scheduled runs without losing any configuration. Manual runs still work while paused. Uninstalling the app pauses every feed automatically.
Inventory locations
If your store has more than one location, an Inventory location card appears on the feed page. The chosen location is used for both sides of the sync: the quantity FeedGuard compares against, and the quantity it writes.
This is the clean way to combine your own stock with supplier stock: keep your warehouse as one location that no feed touches, and give each supplier its own location driven by its feed. Shopify then sells from the combined availability.
Products that disappear from a feed
When a product exists in your store but stops appearing in the feed, the feed's Products not in feed policy decides what happens:
| Policy | Effect |
|---|---|
| Ignore | Nothing happens. The safe default, and right when a feed only covers part of your catalogue. |
| Set stock to zero | Stock is zeroed so the product cannot be oversold. |
| Set to draft | The product is hidden from your storefront. |
| Tag for review | The tag feedguard-not-in-feed is added so you can find and review them in Shopify. |
These actions are counted in the diff like any other change, which means the guardrails see them too — so a truncated file cannot quietly zero your catalogue through this policy.
Creating missing products
Tick Create missing products in the Sync mode card to have FeedGuard add products for feed rows whose SKU is not in your store.
- They are created as drafts, so customers never see them until you publish.
- Title, price, barcode, stock and the feed's image are filled in from your mapping.
- Inventory tracking is enabled and the quantity set at the feed's location.
- Dry runs list every product that would be created before you turn it on.
- Up to 250 products are created per run; the rest follow on the next runs.
It is off by default — adding products to a catalogue should always be a deliberate choice.
Product images
Map an image column to Image URL and FeedGuard will add that image when the product has none. Images are fetched by Shopify from the URL, so the link must be publicly reachable.
Existing images are never replaced or duplicated. Once Shopify hosts an image, its address no longer matches the supplier's URL, so “same photo, new URL” cannot be distinguished from a genuinely new photo — filling only the gaps avoids adding the same picture over and over. If an image link fails, the rest of that product's data still syncs and the URL is retried on the next run.
Setting up alerts
- Go to Alerts.
- Choose when to be notified, pick Email or Slack webhook, and enter the address or webhook URL.
- Press Add alert, then Test on the new row to confirm delivery.
| Alert | Fires when |
|---|---|
| Run failed | Any run ends in failure, for any reason. |
| Guardrail tripped | A circuit breaker stopped a run. Recommended for every feed. |
| Feed file missing | The source had no file to collect. |
| Credentials expired | The source rejected the stored credentials. |
| Row errors during a run | Transform errors, or changes Shopify rejected. |
| Weekly digest | Every Monday: runs, failures and applied changes per feed for the last seven days. |
Alert emails include the feed name, status, the exact error, row counts and the run ID, so you usually know what happened without opening the app. Slack alerts are available on Growth and Pro.
The dashboard
The dashboard shows each feed's health, its last and next run, and a Needs attention panel listing recent failures with a suggested fix for each — for example “the source rejected the credentials — update them in the feed settings”. Below that is a live activity stream of recent runs.
Sharing a run with support
Every run page has Copy support link. It produces a private, read-only web page showing that one run: its stages, stats, warnings and change list — no store access, no credentials, nothing else from your account. Include it when you email support and we can diagnose immediately.
Plans
| Starter | Growth | Pro | |
|---|---|---|---|
| Price per month | $19 | $49 | $99 |
| Feeds | 2 | 10 | Unlimited |
| Fastest schedule | Daily | Hourly | Every 15 minutes |
| Products / SKUs | Unlimited | Unlimited | Unlimited |
| All source types | Yes | Yes | Yes |
| Diff preview, dry runs, guardrails, rollback | Yes | Yes | Yes |
| Product creation and images | Yes | Yes | Yes |
| Email alerts | Yes | Yes | Yes |
| Slack alerts and weekly digest | — | Yes | Yes |
| Priority support | — | — | Yes |
Every plan includes a 14-day free trial. There are no usage fees, no per-row charges and no catalogue-size tiers.
Subscribing, changing and cancelling
Open Billing in the app, choose a plan and approve the subscription on Shopify's confirmation screen. Billing runs entirely through Shopify and appears on your normal Shopify invoice.
Switching plans is one click on the plan you want. Cancelling from the same page returns you to the free trial state and is prorated by Shopify. Your feeds, mappings and history are kept — only the limits change, so if you cancel while using more feeds or a faster schedule than a lower plan allows, adjust those before the change takes effect.
Fetch and connection problems
| Message | Cause and fix |
|---|---|
HTTP 401 / HTTP 403 | The source rejected the credentials. For URLs, check the basic-auth fields or API key header. For Google Sheets, either share the sheet as “anyone with the link can view” or add a service account key. |
HTTP 404 | The link is wrong or the file has been renamed. Open the URL in a browser to confirm it downloads a file. |
| No files matching “*.csv” | The folder or file pattern is wrong, or the supplier has not delivered today's file. Check the directory path and pattern in the source settings. |
| Connection refused / timeout | The host or port is wrong, or the server is down. Confirm the details with your supplier; some FTP servers also restrict access by IP. |
| Google Sheets export failed | The sheet is restricted and no service account key is configured. Follow the private-sheet steps in Connecting a data source. |
| recordsPath did not resolve to an array | For REST feeds: the records path is wrong. Open the API response and note where the product list actually sits, e.g. data.products. |
Mapping and data problems
| Symptom | Cause and fix |
|---|---|
| Everything counted as “Not found” | The match key does not line up. Compare a SKU from the file with the variant SKU in Shopify — a prefix, trailing space or different code system is usually the reason. Add a prefix or trim transform, or switch the match key to Barcode. |
| “Map a SKU column to enable diffing” | No mapping targets SKU. Add one; it is the only required field. |
| Prices come through wrong | The source contains currency symbols or thousands separators. Strip them with a regex replace, and convert decimal commas with find & replace. |
| “value is not a number” | A Math, Round or Stock buffer step received text. Add a Default if empty step, or filter those rows out. |
| Status is not applied | The supplier's wording is not recognised. Add a find & replace or a lookup table to turn it into active or draft. |
| Only the first file in a zip is used | The other files have different columns, so merging them would corrupt the mapping. The run warnings name each skipped file. |
Writing problems
| Symptom | Cause and fix |
|---|---|
| Run succeeded but nothing changed in Shopify | The feed is in dry-run mode. Check the badge in the feed header and enable live mode. |
| Quantities are not updating | Confirm the feed's inventory location matches the location you are looking at in Shopify. FeedGuard switches inventory tracking on automatically, so a previously untracked product simply updates on its next run. |
| Some rows show a red “Error” badge | Shopify rejected those specific writes; the reason is printed next to the badge. Everything else in the run still applied. |
| An image did not appear | Shopify fetches images from the URL, so it must be publicly reachable — links behind a login or hotlink protection fail. The URL is retried on the next run. |
Scheduling problems
| Symptom | Cause and fix |
|---|---|
| Every scheduled run says “Skipped — unchanged” | Working as designed: the source file has not changed. Use Run now to force a run. |
| The schedule I want is greyed out | It is above your plan's frequency limit. Upgrade in Billing. |
| No runs are happening at all | Check that the feed is Active, not Paused, and that a schedule other than “Manual only” is saved. |
Still stuck?
Email support@synovaapps.com with the run's support link (the Copy support link button on the run page). A human replies within 4 business hours.
Inventory questions
Will FeedGuard overwrite stock I manage myself?
Only if you map the quantity field. If your stock sits in your own warehouse, leave Inventory quantity unmapped — FeedGuard will sync prices and product data and leave Shopify's stock alone. If you hold your own stock and resell supplier stock, give the supplier its own Shopify location and point the feed there.
What happens between syncs when I make a sale?
Shopify reduces stock as orders come in, so your number drifts slightly below the supplier's until the next sync. That is the safe direction — it makes overselling less likely, not more. The next sync sets the supplier's current figure again. For fast-moving products, sync more often and add a stock buffer.
Why does the diff show a change when the value looks the same?
It usually is not the same. Numeric fields are compared as numbers, so 10.50 and 10.5 are equal, and tags are compared as a set, so re-ordering them is not a change. If a difference is shown, something genuinely differs — check for trailing spaces or a different number of decimals.
Safety questions
What if my supplier sends a broken file?
That is the case FeedGuard was built for. The run is compared against your live catalogue first, and if the result looks destructive — too much changing, too many products going to zero, or a file that has lost most of its rows — the sync aborts before writing anything and tells you why.
Can I undo a sync?
Yes. Open the run and press Revert this run. Every applied change is written back to its previous value, and the rollback is recorded as its own run.
Can I test without any risk?
Yes — that is the default. New feeds run in dry-run mode and cannot write to your store until you have seen three clean runs and explicitly enabled live mode.
Setup questions
Do I have to reformat my supplier's file?
No. Auto-map matches your file's own headers, and transforms handle margins, rounding, prefixes, unit conversions and status wording. Lookup tables cover supplier-specific codes.
Can one feed update several suppliers' products?
A feed handles one source file. Create one feed per supplier — each with its own mapping, schedule and guardrails.
Can it add products that are not in my store yet?
Yes, optionally. Enable Create missing products and unknown SKUs are created as drafts with price, barcode, stock and image for you to review.
Does it work with private Google Sheets?
Yes, through a Google service account. Public link-shared sheets need no credentials at all.
How large a catalogue can it handle?
There is no SKU limit on any plan. Files with 100,000 rows are processed in seconds; very large catalogues simply spend a little longer reading from Shopify, and runs happen in the background.
Can I copy my setup to another store?
Yes. On the Feeds page use Export all feeds (JSON), then Import feeds in the other store. Sources, mappings, filters and guardrails come across; imported feeds arrive paused so you can review them first. It also makes a useful configuration backup.
Account questions
What does FeedGuard have access to?
Products and inventory only. It cannot see customers, orders or payment data.
What happens if I uninstall?
Access is revoked immediately and all feeds are paused. Shopify then sends a data-deletion request, at which point your feeds, credentials and history are permanently removed.
How fast is support?
A human answers within 4 business hours, including on the Starter plan. Pro customers get priority.
What we store
- Your store address and plan, plus the access token Shopify issues so the app can read and update products on your behalf.
- Feed configuration — sources, mappings, filters and guardrails. Supplier credentials inside that configuration are encrypted at rest with AES-256-GCM and are never displayed back in the interface.
- Feed files and run history — a copy of each processed file and the per-run change logs, kept so runs can be audited and reverted.
What we never store
No customer data of any kind: no names, addresses, orders or payment details. The app requests product and inventory permissions only, so it has no technical means to read them.
How the app protects your catalogue
- Dry-run by default, and live mode only after three reviewed runs.
- Guardrails that stop destructive syncs before any write.
- A complete before-and-after record of every change, with one-click rollback.
- Per-change error reporting, so a partial failure is visible rather than silent.
Deletion
Uninstalling revokes access and pauses everything. Shopify's shop/redact request — sent 48 hours after uninstall — permanently deletes your store's feeds, credentials, run history and change logs. Because no customer data is held, customer-data requests have nothing to return or erase.
Sub-processors
- Shopify — platform APIs.
- Resend — delivery of the alert emails you configure.
- Crisp — in-app support chat, when enabled.
Full details are in the privacy policy. Questions and data requests: support@synovaapps.com.