Install GeoSwap from the Shopify App Store — no code editing required
The GeoSwap Shopify app lets you add geo-targeting to your store without touching any code. Install from the App Store, connect your GeoSwap workspace, turn on the app embed, and your geo rules start working.
Already using GeoSwap with a manual script tag? The Shopify app replaces the manual theme.liquid installation described in the Installation Guide. You can use either method, but the app is simpler and doesn't require code access.
The Shopify app is a lightweight connector between your store and GeoSwap. Here's what happens under the hood:
The app adds an app embed that loads geoswap.js in your storefront's <head>. You switch it on in the theme editor. Your theme files are never edited.
When you connect a workspace, the app writes your project ID to a shop metafield. The theme block reads it automatically — no copy-pasting IDs. If you switch workspaces, the metafield updates and the change takes effect on the next page load.
All geo rules are evaluated server-side by GeoSwap's edge network. Search engine crawlers always see your original content — no cloaking, no SEO risk. This works identically to the manual installation.
Search for "GeoSwap" in the Shopify App Store, or use the direct link from geoswap.co. Click Install and approve the permissions.
The app only asks for theme access (read_themes and write_themes). GeoSwap uses it to save your Project ID to your store as a shop metafield, which the app embed reads. It never edits your theme files and has no access to orders, customers, or products.
GeoSwap is a non-embedded app: clicking it in your Shopify Admin opens GeoSwap itself. Right after you install, Shopify sends you there.
Your store is now linked. Any geo rules you create in that workspace will apply to your Shopify store. To come back later, open GeoSwap from your Shopify Admin at any time.
The app installs an app embed (a theme app extension that adds one script to your theme's <head>). Shopify requires you to switch it on once in the theme editor:
Prefer to do it by hand? Online Store → Themes → Customize → the App embeds icon in the left sidebar → toggle GeoSwap Geo Targeting on → Save.
The app embed won't switch itself on
Shopify requires merchants to switch app embeds on themselves. Until it is on, geo rules won't apply to your storefront. Re-activating an embed that is already on does nothing, so the button above is always safe to click.
You're already in the GeoSwap dashboard. From the sidebar you can:
Geo Redirects: Send visitors from France to your .fr store, visitors from Germany to your .de store, etc.
Geo Content: Show different pricing, banners, or CTAs based on visitor location.
Geo Links: Create short links that route to different URLs by country.
Shopify checkout and the order confirmation page don't run theme scripts, so geoswap.track() can't see a purchase there. A Shopify custom pixel can. It sends each completed order to GeoSwap Attribution as a purchase, with its order ID, total, currency and discount codes, and credits it to the visit that brought the customer in (UTMs, ad click ids, GeoSwap links). The same pixel also sends add to cart and checkout started to the Funnel (those are funnel steps, never conversions). If you installed an earlier GeoSwap pixel (one without v2 in its first lines doesn't send discount codes or region), replace it with this one. The GeoSwap storefront script also detects add to cart and checkout on its own, deduplicated with the pixel, so you don't lose Funnel data if a visitor's browser blocks the pixel.
In your GeoSwap dashboard open Foundations → Sites & script and click Copy pixel code in the Shopify checkout card. Your Project ID is already in it. (The code is below too; replace YOUR_PROJECT_ID.)
In Shopify Admin go to Settings → Customer events, click Add custom pixel, name it "GeoSwap" and paste the code in place of everything in the code box. Pick the Customer privacy setting that matches your store's consent policy.
Click Save, then Connect. Purchases show up on the Attribution page within about three hours (see how attribution works).
// GeoSwap: send Shopify purchases (attribution) and cart/checkout steps (Funnel) to GeoSwap.
// v2: discount codes + region
// Paste into Shopify Admin > Settings > Customer events > Add custom pixel.
// Replaces any earlier GeoSwap pixel: keep only this one.
const GEOSWAP_PROJECT = "YOUR_PROJECT_ID";
const GEOSWAP_ENDPOINT = "https://edge.geoswap.co/t";
// Address fields sent with each order (GeoSwap: Sites & script > Conversion address).
const GEOSWAP_ADDRESS = ["region"];
analytics.subscribe("checkout_completed", async (event) => {
try {
const checkout = event.data.checkout;
const page = (event.context || init.context).document.location;
// Visitor + session ids the GeoSwap script saved on your storefront.
const vidCookie = (await browser.cookie.get("gs_vid")) || "";
const sessionId = ((await browser.cookie.get("gs_sid")) || "").split(".")[0];
let session = {};
try {
session = JSON.parse(await browser.localStorage.getItem("gs_s_" + GEOSWAP_PROJECT)) || {};
} catch (e) {}
if (!sessionId || session.sid != sessionId) session = {};
const orderId = checkout.order && checkout.order.id;
const total = checkout.totalPrice || {};
// Discount codes, in the order applied (automatic discounts aren't codes).
const codes = [];
for (const d of checkout.discountApplications || []) {
const code = d && d.type === "DISCOUNT_CODE" && typeof d.title === "string" ? d.title.trim() : "";
if (code && codes.length < 5 && !codes.some((c) => c.toUpperCase() === code.toUpperCase())) codes.push(code);
}
// Shipping address, else billing (digital goods).
const addr = checkout.shippingAddress || checkout.billingAddress || {};
const sends = (field) => GEOSWAP_ADDRESS.indexOf(field) >= 0;
const body = {
projectId: GEOSWAP_PROJECT,
url: "https://" + page.hostname + "/",
e: "purchase",
vid: /^[\w-]{16}\.\d{8}$/.test(vidCookie) ? vidCookie.slice(0, 16) : undefined,
c: session.c || undefined,
r: session.r || undefined,
id: orderId ? String(orderId).split("/").pop() : checkout.token || undefined,
v: total.amount != null ? Number(total.amount) : undefined,
cur: total.currencyCode || checkout.currencyCode || undefined,
k: codes,
co: sends("region") ? addr.countryCode || undefined : undefined,
st: sends("region") ? addr.provinceCode || undefined : undefined,
zp: sends("postal") ? addr.zip || undefined : undefined,
ci: sends("city") ? addr.city || undefined : undefined,
};
await fetch(GEOSWAP_ENDPOINT, {
method: "POST",
mode: "no-cors",
credentials: "omit",
keepalive: true,
body: JSON.stringify(body),
});
} catch (e) {}
});
// Funnel steps (never conversions): add to cart and checkout started.
async function geoswapFunnelEvent(eventName, event) {
try {
const page = (event.context || init.context).document.location;
const vidCookie = (await browser.cookie.get("gs_vid")) || "";
await fetch(GEOSWAP_ENDPOINT, {
method: "POST",
mode: "no-cors",
credentials: "omit",
keepalive: true,
body: JSON.stringify({
projectId: GEOSWAP_PROJECT,
url: "https://" + page.hostname + "/",
e: eventName,
vid: /^[\w-]{16}\.\d{8}$/.test(vidCookie) ? vidCookie.slice(0, 16) : undefined,
}),
});
} catch (e) {}
}
analytics.subscribe("product_added_to_cart", (event) => geoswapFunnelEvent("product_added_to_cart", event));
analytics.subscribe("checkout_started", (event) => geoswapFunnelEvent("checkout_started", event));
The pixel reads the visitor id the GeoSwap script (the app embed, or the script tag) saves on your storefront, so the purchase joins that visitor's earlier visits. If a browser blocks it, GeoSwap still matches same-day visits from that browser.
Your store's domain, the visitor and session ids GeoSwap set, the Shopify order ID, the order total and its currency, the discount codes used, and the shipping (else billing) country and province. ZIP code and city are sent only when you turn on Store postal code and city in GeoSwap (Foundations → Sites & script; re-paste the pixel after changing it). It never sends the customer's email, phone or street address. Discount codes are stored for an upcoming feature and don't change credit yet. An order sent twice is counted once. If you also send purchases from your server, use the same Shopify order ID as id.
Make sure the domain your checkout runs on is in your site list (usually your store's main domain). Purchases from a domain that isn't listed are dropped.
Use the built-in Rule Simulator in your GeoSwap dashboard to test geo rules without being in another country. The simulator lets you pick any country, state, or city and see exactly which rule would fire for that visitor.
Open your GeoSwap dashboard and go to Geo Tools → Simulate Rules.
Pick the entity type (redirect, link, or content rule), choose the rule, and select a country.
Click Simulate. You'll see which of that rule's variants fires for a visitor from that location, and where they'd be sent.
On the workspace's Shopify page click Change plan. Shopify's pricing page lets you upgrade, downgrade to Free, or cancel at any time; the change shows in your Shopify app charges and takes effect in GeoSwap as soon as you return.
Disconnect the store in Settings → Workspace, then open GeoSwap from Shopify Admin again and pick the new workspace. The Project ID updates for you, so there's no need to edit your theme.
Workspace admins can click Disconnect Shopify in Settings → Workspace. This removes the workspace link but keeps the app installed. The app embed stays in your theme but stops applying geo rules. You can reconnect a workspace at any time. If you pay for a plan through Shopify, move to the Free plan first (Shopify page → Change plan); the disconnect button appears after that.
Uninstall the app from Settings → Apps and sales channels in your Shopify Admin. This removes the workspace link, revokes the access token, and ends any plan billed through Shopify (the workspace moves to Free). If you reinstall later, you'll need to reconnect your workspace.
No. The GeoSwap script is under 5KB gzipped, loaded with the `defer` attribute, and served from a global CDN. It doesn't block page rendering.
No. All geo decisions are made server-side. Search engine crawlers (Google, Bing, etc.) always see your original content. GeoSwap never cloaks or hides content from bots.
Yes. GeoSwap works independently from Shopify Markets. You can use both — for example, Shopify Markets for currency/language and GeoSwap for geo redirects to entirely different domains.
Theme access only (`read_themes` and `write_themes`). GeoSwap uses it to save your Project ID as a shop metafield for the app embed. It cannot access your orders, customers, products, or any other store data, and it never edits your theme files.
App embeds are switched on per theme, so turn on GeoSwap Geo Targeting in your new theme (the Activate in theme editor button does it). The workspace connection stays intact.
Learn how to create geo redirect rules.