diff --git a/.env.example b/.env.example
index 1c636c5..b4d91c8 100644
--- a/.env.example
+++ b/.env.example
@@ -2,5 +2,5 @@
APP_DOMAIN=bundles.example.com
SHOPIFY_API_KEY=your_client_id
SHOPIFY_API_SECRET=your_client_secret
-SHOPIFY_APP_HANDLE=bundle-offers
+SHOPIFY_APP_HANDLE=offerlyst
POSTGRES_PASSWORD=change-me-to-a-long-random-string
diff --git a/Dockerfile b/Dockerfile
index 861fad1..d0871d6 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-# Bundle Offers web app (admin, app proxy, webhooks, scheduler). The Shopify extensions are deployed
+# Offerlyst web app (admin, app proxy, webhooks, scheduler). The Shopify extensions are deployed
# separately with `shopify app deploy`.
FROM node:22-alpine AS build
RUN apk add --no-cache openssl
diff --git a/README.md b/README.md
index 077ba81..e909113 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
-# Bundle Offers (Shopify app)
+# Offerlyst: Bundles & BOGO (Shopify app)
+
+Brand assets: `brand/` (App Store icon `offerlyst-icon-1200.png`).
Public Shopify app that re-creates the ClicksToCart Odoo module `c2c_bundle_offers`: fixed bundles, mix & match
and buy X get Y, applied by **one** automatic app discount whose function evaluates every running offer in
diff --git a/app/lib/orders.server.ts b/app/lib/orders.server.ts
index 2c8ef18..8940754 100644
--- a/app/lib/orders.server.ts
+++ b/app/lib/orders.server.ts
@@ -1,6 +1,6 @@
// orders/create -> analytics (F23, N02). The function's candidate message is the offer name, or "A + B" when
// one line carries two offers; we attribute by name. If Shopify reports only the discount title
-// ("Bundle Offers"), the usage is kept under that title. Verify the exact title on a dev store (README).
+// (DISCOUNT_TITLE, "Offerlyst bundles"), the usage is kept under that title. Verify the exact title on a dev store (README).
import db from "../db.server";
export interface OrderPayload {
diff --git a/app/lib/publish.server.ts b/app/lib/publish.server.ts
index 63685c8..5d88403 100644
--- a/app/lib/publish.server.ts
+++ b/app/lib/publish.server.ts
@@ -6,7 +6,7 @@ import { compile, settingsOf, type CompileResult } from "./compile";
import { gql, ensureShop, type AdminLike } from "./shop.server";
export const FUNCTION_HANDLE = "bundle-discount";
-export const DISCOUNT_TITLE = "Bundle Offers";
+export const DISCOUNT_TITLE = "Offerlyst bundles";
export const STOREFRONT_NAMESPACE = "bundle_offers";
const CREATE = `#graphql
@@ -94,7 +94,7 @@ async function ensureDiscount(admin: AdminLike, shop: { id: string; discountNode
},
});
const err = userErrorText(data.discountAutomaticAppCreate.userErrors);
- if (err) throw new Error(`Could not create the Bundle Offers discount: ${err}`);
+ if (err) throw new Error(`Could not create the Offerlyst discount: ${err}`);
const id = data.discountAutomaticAppCreate.automaticAppDiscount.discountId as string;
await db.shop.update({ where: { id: shop.id }, data: { discountNodeId: id } });
return { id, created: true };
diff --git a/app/lib/storefront.server.ts b/app/lib/storefront.server.ts
index b15e3fd..ffd9bfe 100644
--- a/app/lib/storefront.server.ts
+++ b/app/lib/storefront.server.ts
@@ -106,7 +106,7 @@ export function bundlesListLiquid(offers: OfferWithRelations[], shop: ShopCtx, l
return `
Bundle offers
${body}
- ${shop.branding ? `Bundles by Bundle Offers
` : ""}
+ ${shop.branding ? `Bundles by Offerlyst
` : ""}
`;
}
diff --git a/app/routes/_index/route.tsx b/app/routes/_index/route.tsx
index fbcfa72..fd3284f 100644
--- a/app/routes/_index/route.tsx
+++ b/app/routes/_index/route.tsx
@@ -21,7 +21,7 @@ export default function App() {
return (
-
Bundle Offers: run all your festival deals at once
+
Offerlyst: run all your bundle deals at once
Fixed bundles, mix & match and buy X get Y, applied automatically at checkout. Each item counts towards one offer, in the order you choose.
diff --git a/app/routes/app._index.tsx b/app/routes/app._index.tsx
index 6bade3c..fdfe35b 100644
--- a/app/routes/app._index.tsx
+++ b/app/routes/app._index.tsx
@@ -78,7 +78,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
export default function Home() {
const d = useLoaderData
();
const steps = [
- { done: d.setup.embedOn, label: "Turn on the Bundle Offers app embed", help: "Loads the storefront script and styles (cart hints, add bundle to cart).", action: Open theme editor },
+ { done: d.setup.embedOn, label: "Turn on the Offerlyst app embed", help: "Loads the storefront script and styles (cart hints, add bundle to cart).", action: Open theme editor },
{ done: d.menuLinked, label: "Link the bundles page in your menu", help: "Your bundles page is at /apps/bundles. Add it to the main menu (Online Store › Navigation), or place the “Bundles grid” block on any page.", action: Open navigation },
{ done: d.totalOffers > 0, label: "Create your first offer", help: "Start from scratch or from a festival template.", action: Create offer },
{ done: d.running.length > 0, label: "Publish an offer and preview it", help: "Published offers within their dates run automatically in cart and checkout.", action: View bundles page },
@@ -86,7 +86,7 @@ export default function Home() {
const doneCount = steps.filter((s) => s.done).length;
return (
-
+
Create offer
{d.shop.publishError ? (
diff --git a/app/routes/app.plans.tsx b/app/routes/app.plans.tsx
index 17e79a0..ac3a165 100644
--- a/app/routes/app.plans.tsx
+++ b/app/routes/app.plans.tsx
@@ -10,7 +10,7 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
const { admin, session } = await authenticate.admin(request);
const shop = await syncShop(admin, session.shop); // refresh the plan from activeSubscriptions
const store = session.shop.replace(".myshopify.com", "");
- const handle = process.env.SHOPIFY_APP_HANDLE || "bundle-offers";
+ const handle = process.env.SHOPIFY_APP_HANDLE || "offerlyst";
return {
current: shop.planCode,
pricingUrl: `https://admin.shopify.com/store/${store}/charges/${handle}/pricing_plans`,
diff --git a/app/routes/privacy.tsx b/app/routes/privacy.tsx
index 9229f16..59e014c 100644
--- a/app/routes/privacy.tsx
+++ b/app/routes/privacy.tsx
@@ -1,7 +1,7 @@
// Public privacy policy (required for the App Store listing): https:///privacy
import type { MetaFunction } from "react-router";
-export const meta: MetaFunction = () => [{ title: "Privacy policy · FestiveBundle" }];
+export const meta: MetaFunction = () => [{ title: "Privacy policy · Offerlyst" }];
const CONTACT = "info@metatroncubesolutions.com";
@@ -9,7 +9,7 @@ export default function Privacy() {
return (
Privacy policy
- Last updated: October 13, 2026. This policy explains what the FestiveBundle app (by Metatroncube Software Solutions) collects when a merchant installs it on a Shopify store.
+ Last updated: October 14, 2026. This policy explains what the Offerlyst app (by Metatroncube Software Solutions) collects when a merchant installs it on a Shopify store.
What we collect
diff --git a/app/routes/webhooks.app.uninstalled.tsx b/app/routes/webhooks.app.uninstalled.tsx
index 5d241ce..ca91907 100644
--- a/app/routes/webhooks.app.uninstalled.tsx
+++ b/app/routes/webhooks.app.uninstalled.tsx
@@ -5,7 +5,7 @@ import db from "../db.server";
// The access token is already revoked here, so the app can't call the Admin API. Shopify removes the app's
// functions with the app, so the automatic discount stops applying, and it deletes app-owned ($app and
// app-data) metafields. We mark the shop and keep its data for 48 h, until shop/redact deletes it.
-// The in-app "Remove all Bundle Offers data" action (Settings) deletes the discount explicitly.
+// The in-app "Remove all Offerlyst data" action (Settings) deletes the discount explicitly.
export const action = async ({ request }: ActionFunctionArgs) => {
const { shop, session, topic } = await authenticate.webhook(request);
console.log(`Received ${topic} webhook for ${shop}`);
diff --git a/app/routes/webhooks.compliance.tsx b/app/routes/webhooks.compliance.tsx
index 97657b6..8d5853b 100644
--- a/app/routes/webhooks.compliance.tsx
+++ b/app/routes/webhooks.compliance.tsx
@@ -2,7 +2,7 @@ import type { ActionFunctionArgs } from "react-router";
import { authenticate } from "../shopify.server";
import db from "../db.server";
-// Mandatory GDPR webhooks. Bundle Offers stores no customer personal data: only order ids, order names and
+// Mandatory GDPR webhooks. Offerlyst stores no customer personal data: only order ids, order names and
// amounts for analytics (no names, emails or addresses). customers/data_request and customers/redact have
// nothing to return or erase; shop/redact (48 h after uninstall) deletes everything about the shop.
export const action = async ({ request }: ActionFunctionArgs) => {
diff --git a/brand/offerlyst-brand-board.png b/brand/offerlyst-brand-board.png
new file mode 100644
index 0000000..814697a
Binary files /dev/null and b/brand/offerlyst-brand-board.png differ
diff --git a/brand/offerlyst-icon-1200.png b/brand/offerlyst-icon-1200.png
new file mode 100644
index 0000000..62ddacd
Binary files /dev/null and b/brand/offerlyst-icon-1200.png differ
diff --git a/brand/offerlyst-icon-256.png b/brand/offerlyst-icon-256.png
new file mode 100644
index 0000000..e291809
Binary files /dev/null and b/brand/offerlyst-icon-256.png differ
diff --git a/brand/offerlyst-icon-64.png b/brand/offerlyst-icon-64.png
new file mode 100644
index 0000000..43750f3
Binary files /dev/null and b/brand/offerlyst-icon-64.png differ
diff --git a/brand/offerlyst-logo-horizontal.png b/brand/offerlyst-logo-horizontal.png
new file mode 100644
index 0000000..dbb6f5b
Binary files /dev/null and b/brand/offerlyst-logo-horizontal.png differ
diff --git a/brand/offerlyst-symbol-transparent.png b/brand/offerlyst-symbol-transparent.png
new file mode 100644
index 0000000..587d114
Binary files /dev/null and b/brand/offerlyst-symbol-transparent.png differ
diff --git a/docker-compose.yml b/docker-compose.yml
index 09daf8d..e59c43e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -28,7 +28,7 @@ services:
SHOPIFY_API_KEY: ${SHOPIFY_API_KEY:?set SHOPIFY_API_KEY in .env}
SHOPIFY_API_SECRET: ${SHOPIFY_API_SECRET:?set SHOPIFY_API_SECRET in .env}
SHOPIFY_APP_URL: https://${APP_DOMAIN:?set APP_DOMAIN in .env}
- SHOPIFY_APP_HANDLE: ${SHOPIFY_APP_HANDLE:-bundle-offers}
+ SHOPIFY_APP_HANDLE: ${SHOPIFY_APP_HANDLE:-offerlyst}
SCOPES: read_products,write_discounts,read_discounts,read_orders,write_files,read_themes,write_app_proxy
expose:
- "3000"
diff --git a/extensions/bundle-discount/locales/en.default.json b/extensions/bundle-discount/locales/en.default.json
index a104f7f..f30eaf8 100644
--- a/extensions/bundle-discount/locales/en.default.json
+++ b/extensions/bundle-discount/locales/en.default.json
@@ -1,4 +1,4 @@
{
- "name": "Bundle Offers",
+ "name": "Offerlyst bundles",
"description": "Applies fixed, mix & match and buy X get Y bundle discounts. Each item counts towards one offer, in priority order."
}
diff --git a/extensions/bundle-discount/shopify.extension.toml b/extensions/bundle-discount/shopify.extension.toml
index 3ce0bd4..9764dab 100644
--- a/extensions/bundle-discount/shopify.extension.toml
+++ b/extensions/bundle-discount/shopify.extension.toml
@@ -1,4 +1,4 @@
-# Bundle Offers: ONE automatic app discount per shop runs this function, which evaluates every running offer.
+# Offerlyst: ONE automatic app discount per shop runs this function, which evaluates every running offer.
# Rust (not JS): the JS build needed 39M instructions just to read a 200-line cart (limit 11M). See README.
api_version = "2026-07"
diff --git a/extensions/bundle-offers-theme/assets/bundle-offers.css b/extensions/bundle-offers-theme/assets/bundle-offers.css
index 81eaa78..8930596 100644
--- a/extensions/bundle-offers-theme/assets/bundle-offers.css
+++ b/extensions/bundle-offers-theme/assets/bundle-offers.css
@@ -1,4 +1,4 @@
-/* Bundle Offers storefront styles.
+/* Offerlyst storefront styles.
Inherits the theme: fonts, text colour and background come from the page. Lines are a mix of the text
colour, so they work on light and dark themes alike. The merchant can set an accent and a radius (Settings).
The one decorative device is the coupon stub on the badge: festival offers as tear-off coupons. */
diff --git a/extensions/bundle-offers-theme/assets/bundle-offers.js b/extensions/bundle-offers-theme/assets/bundle-offers.js
index fb49fed..6834d9a 100644
--- a/extensions/bundle-offers-theme/assets/bundle-offers.js
+++ b/extensions/bundle-offers-theme/assets/bundle-offers.js
@@ -1,4 +1,4 @@
-/* Bundle Offers storefront script (app embed). Vanilla JS, no dependencies.
+/* Offerlyst storefront script (app embed). Vanilla JS, no dependencies.
* - converts shop-currency deal amounts when the customer shops in another currency
* - bundle pages (/apps/bundles/...): quantity steppers, "N of M chosen", add all items in one request
* - refreshes cart hints after AJAX cart changes */
diff --git a/extensions/bundle-offers-theme/blocks/bundle-offers-embed.liquid b/extensions/bundle-offers-theme/blocks/bundle-offers-embed.liquid
index d103b6b..0e03531 100644
--- a/extensions/bundle-offers-theme/blocks/bundle-offers-embed.liquid
+++ b/extensions/bundle-offers-theme/blocks/bundle-offers-embed.liquid
@@ -27,7 +27,7 @@
{% schema %}
{
- "name": "Bundle Offers",
+ "name": "Offerlyst",
"target": "body",
"javascript": "bundle-offers.js",
"stylesheet": "bundle-offers.css",
diff --git a/extensions/bundle-offers-theme/blocks/bundles-grid.liquid b/extensions/bundle-offers-theme/blocks/bundles-grid.liquid
index e8ea790..d25c3c6 100644
--- a/extensions/bundle-offers-theme/blocks/bundles-grid.liquid
+++ b/extensions/bundle-offers-theme/blocks/bundles-grid.liquid
@@ -17,7 +17,7 @@
{{ 'bundle_offers.grid.continue' | t }}
{%- endif -%}
- {%- if data.brand -%}
Bundles by Bundle Offers
{%- endif -%}
+ {%- if data.brand -%}
Bundles by Offerlyst
{%- endif -%}
{% schema %}
diff --git a/extensions/bundle-offers-theme/shopify.extension.toml b/extensions/bundle-offers-theme/shopify.extension.toml
index 948ac4b..dea106c 100644
--- a/extensions/bundle-offers-theme/shopify.extension.toml
+++ b/extensions/bundle-offers-theme/shopify.extension.toml
@@ -1,2 +1,2 @@
-name = "Bundle Offers storefront"
+name = "Offerlyst storefront"
type = "theme"
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 9c53550..d1b2511 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -1,4 +1,4 @@
-// Bundle Offers app database (brief §14). Postgres.
+// Offerlyst app database (brief §14). Postgres.
generator client {
provider = "prisma-client-js"
}
diff --git a/shopify.app.toml b/shopify.app.toml
index 92675b4..324dfc9 100644
--- a/shopify.app.toml
+++ b/shopify.app.toml
@@ -1,7 +1,8 @@
-# Bundle Offers — Shopify app configuration.
+# Offerlyst — Shopify app configuration.
# Run `npm run config:link` once to connect this folder to your app in the Partner Dashboard (fills client_id).
client_id = ""
-name = "Bundle Offers"
+name = "Offerlyst: Bundles & BOGO"
+handle = "offerlyst"
application_url = "https://example.com"
embedded = true