diff --git a/src/app/(dashboard)/dashboard/CheaperInferenceSponsorBanner.tsx b/src/app/(dashboard)/dashboard/CheaperInferenceSponsorBanner.tsx
new file mode 100644
index 0000000000..77cf193298
--- /dev/null
+++ b/src/app/(dashboard)/dashboard/CheaperInferenceSponsorBanner.tsx
@@ -0,0 +1,108 @@
+"use client";
+
+import { useSyncExternalStore } from "react";
+import { useTranslations } from "next-intl";
+import ProviderIcon from "@/shared/components/ProviderIcon";
+
+// Branded short link through our own link.omniroute.online shortener, so the
+// click lands in our Kutt metrics. Points at cheaperinference.com?utm_source=omniroute
+// (the URL in README.md's Open Source Friends section). Keep in sync with the
+// `cheaper` slug on the shortener.
+const CHEAPER_INFERENCE_URL = "https://link.omniroute.online/cheaper";
+
+// Cheaper Inference brand green (#31f889). White text on it fails contrast, so
+// the CTA pairs it with the dark ink from the provider's color token (colors.ts:
+// cheaperinference.text = #04170d). Hex values stay in sync with that token.
+
+const DISMISS_STORAGE_KEY = "omniroute-cheaperinference-sponsor-banner-dismissed-v1";
+// Same-tab signal for the dismiss button, since writing localStorage doesn't
+// fire a "storage" event in the tab that wrote it.
+const DISMISS_EVENT = "omniroute:cheaperinference-sponsor-banner-dismissed";
+
+function isNotDismissed(): boolean {
+ try {
+ return !localStorage.getItem(DISMISS_STORAGE_KEY);
+ } catch {
+ return true;
+ }
+}
+
+function subscribe(callback: () => void) {
+ window.addEventListener(DISMISS_EVENT, callback);
+ return () => window.removeEventListener(DISMISS_EVENT, callback);
+}
+
+// SSR has no localStorage, so the server always renders the banner visible;
+// useSyncExternalStore reconciles that against the real client-side value
+// right after hydration, mirroring KimiSponsorBanner's pattern.
+function getServerSnapshot() {
+ return true;
+}
+
+/**
+ * Dismissable banner announcing the Cheaper Inference OmniRoute partnership on
+ * the dashboard home page — same size/shape as KimiSponsorBanner, no version
+ * gate (durable partnership, not a time-boxed offer). The logomark reuses
+ * .
+ */
+export default function CheaperInferenceSponsorBanner() {
+ const t = useTranslations("cheaperInferenceSponsorBanner");
+ const visible = useSyncExternalStore(subscribe, isNotDismissed, getServerSnapshot);
+
+ if (!visible) {
+ return null;
+ }
+
+ const dismiss = () => {
+ try {
+ localStorage.setItem(DISMISS_STORAGE_KEY, "true");
+ } catch {
+ // ignore — worst case the banner reappears next visit
+ }
+ window.dispatchEvent(new Event(DISMISS_EVENT));
+ };
+
+ return (
+
+
+
+
+
{t("title")}
+
{t("description")}
+
+
+
+
+
+ );
+}
diff --git a/src/app/(dashboard)/dashboard/VscodeCopilotBanner.tsx b/src/app/(dashboard)/dashboard/VscodeCopilotBanner.tsx
index 0b23976531..1715f17c83 100644
--- a/src/app/(dashboard)/dashboard/VscodeCopilotBanner.tsx
+++ b/src/app/(dashboard)/dashboard/VscodeCopilotBanner.tsx
@@ -6,7 +6,9 @@ import { useTranslations } from "next-intl";
// Marketplace listing is the primary CTA; Open VSX (Cursor/Windsurf/VSCodium/etc.)
// is called out via secondaryNote instead of a second button, to keep this banner
// the same size as KimiSponsorBanner.
-const MARKETPLACE_URL = "https://marketplace.visualstudio.com/items?itemName=diegosouzapw.omnicopilot";
+// Branded short link through our own link.omniroute.online shortener (the `vsx`
+// slug), so the click lands in our Kutt metrics.
+const MARKETPLACE_URL = "https://link.omniroute.online/vsx";
const DISMISS_STORAGE_KEY = "omniroute-vscode-copilot-banner-dismissed-v1";
// Same-tab signal for the dismiss button, since writing localStorage doesn't
diff --git a/src/app/(dashboard)/home/page.tsx b/src/app/(dashboard)/home/page.tsx
index beccde2261..bc10df88f4 100644
--- a/src/app/(dashboard)/home/page.tsx
+++ b/src/app/(dashboard)/home/page.tsx
@@ -4,6 +4,7 @@ import { getSettings } from "@/lib/localDb";
import HomePageClient from "../dashboard/HomePageClient";
import BootstrapBanner from "../dashboard/BootstrapBanner";
import KimiSponsorBanner from "../dashboard/KimiSponsorBanner";
+import CheaperInferenceSponsorBanner from "../dashboard/CheaperInferenceSponsorBanner";
import VscodeCopilotBanner from "../dashboard/VscodeCopilotBanner";
import NewsBanner from "../dashboard/NewsBanner";
@@ -20,6 +21,7 @@ export default async function HomePage() {
<>
{isBootstrapped && }
+
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index ff778753c6..930f5b5958 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -13869,5 +13869,12 @@
"toolsMismatch": "Provider does not support tool calling",
"structuredOutputMismatch": "Provider does not support structured output",
"contextWindowMismatch": "Request exceeds provider context window"
+ },
+ "cheaperInferenceSponsorBanner": {
+ "title": "Cheaper Inference is an OmniRoute Open Source Friend",
+ "description": "A cost-ranked gateway reselling dozens of frontier models behind one OpenAI-compatible endpoint — routing each request to the cheapest eligible provider, never above list price.",
+ "cta": "Get an API Key",
+ "partnerLinkNote": "Partner link",
+ "dismissAriaLabel": "Dismiss"
}
}
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 11a3606a54..1921f3fba7 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -13845,5 +13845,12 @@
"toolsMismatch": "Provider does not support tool calling",
"structuredOutputMismatch": "Provider does not support structured output",
"contextWindowMismatch": "Request exceeds provider context window"
+ },
+ "cheaperInferenceSponsorBanner": {
+ "title": "A Cheaper Inference é uma Amiga do Código Aberto do OmniRoute",
+ "description": "Um gateway com custo ordenado que revende dezenas de modelos de fronteira num único endpoint compatível com OpenAI — roteando cada requisição ao provedor elegível mais barato, nunca acima do preço de tabela.",
+ "cta": "Obter uma Chave de API",
+ "partnerLinkNote": "Link de parceiro",
+ "dismissAriaLabel": "Dispensar"
}
}
diff --git a/tests/unit/ui/cheaperInferenceSponsorBanner.test.tsx b/tests/unit/ui/cheaperInferenceSponsorBanner.test.tsx
new file mode 100644
index 0000000000..b86f4188c6
--- /dev/null
+++ b/tests/unit/ui/cheaperInferenceSponsorBanner.test.tsx
@@ -0,0 +1,92 @@
+// @vitest-environment jsdom
+/**
+ * CheaperInferenceSponsorBanner — render gate (localStorage dismissal), CTA
+ * pointing at our link.omniroute.online branded short link, and discreet
+ * partner-link note. Mirrors kimiSponsorBanner.test.tsx, minus the version gate
+ * (this banner is a durable partnership, not a time-boxed offer).
+ */
+import React from "react";
+import { act } from "react";
+import { createRoot } from "react-dom/client";
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+
+const STORAGE_KEY = "omniroute-cheaperinference-sponsor-banner-dismissed-v1";
+const DISMISS_EVENT = "omniroute:cheaperinference-sponsor-banner-dismissed";
+const SHORT_URL = "https://link.omniroute.online/cheaper";
+
+vi.mock("next-intl", () => ({ useTranslations: () => (k: string) => k }));
+vi.mock("@/shared/components/ProviderIcon", () => ({ default: () => null }));
+
+async function renderBanner(): Promise {
+ vi.resetModules();
+ const { default: CheaperInferenceSponsorBanner } =
+ await import("../../../src/app/(dashboard)/dashboard/CheaperInferenceSponsorBanner");
+
+ const container = document.createElement("div");
+ document.body.appendChild(container);
+ const root = createRoot(container);
+ act(() => {
+ root.render();
+ });
+ return container;
+}
+
+describe("CheaperInferenceSponsorBanner", () => {
+ beforeEach(() => {
+ (
+ globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
+ ).IS_REACT_ACT_ENVIRONMENT = true;
+ localStorage.removeItem(STORAGE_KEY);
+ });
+
+ afterEach(() => {
+ document.body.innerHTML = "";
+ localStorage.removeItem(STORAGE_KEY);
+ });
+
+ it("renders with the CTA pointing at the branded short link", async () => {
+ const container = await renderBanner();
+ expect(container.textContent).toContain("title");
+ expect(container.textContent).toContain("cta");
+ const link = container.querySelector("a[href]");
+ expect(link).not.toBeNull();
+ expect(link?.getAttribute("href")).toBe(SHORT_URL);
+ expect(link?.getAttribute("target")).toBe("_blank");
+ expect(link?.getAttribute("rel")).toContain("noopener");
+ });
+
+ it("shows the discreet partner-link note near the CTA", async () => {
+ const container = await renderBanner();
+ expect(container.textContent).toContain("partnerLinkNote");
+ const link = container.querySelector("a[href]");
+ expect(link?.getAttribute("title")).toBe("partnerLinkNote");
+ });
+
+ it("hides after dismissal and stays hidden on re-render", async () => {
+ const first = await renderBanner();
+ const button = first.querySelector("button");
+ expect(button).not.toBeNull();
+ act(() => {
+ button?.click();
+ });
+ expect(localStorage.getItem(STORAGE_KEY)).toBe("true");
+ expect(first.textContent).not.toContain("title");
+
+ // a fresh render (simulating a later visit) stays hidden
+ const second = await renderBanner();
+ expect(second.textContent).not.toContain("title");
+ });
+
+ it("re-renders visible again only after the key is cleared", async () => {
+ const first = await renderBanner();
+ const button = first.querySelector("button");
+ act(() => {
+ button?.click();
+ });
+ expect(localStorage.getItem(STORAGE_KEY)).toBe("true");
+
+ localStorage.removeItem(STORAGE_KEY);
+ const second = await renderBanner();
+ expect(second.textContent).toContain("title");
+ });
+});
diff --git a/tests/unit/ui/vscodeCopilotBanner.test.tsx b/tests/unit/ui/vscodeCopilotBanner.test.tsx
index ed75ad4950..fad50b2b26 100644
--- a/tests/unit/ui/vscodeCopilotBanner.test.tsx
+++ b/tests/unit/ui/vscodeCopilotBanner.test.tsx
@@ -11,7 +11,7 @@ import { createRoot } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const STORAGE_KEY = "omniroute-vscode-copilot-banner-dismissed-v1";
-const MARKETPLACE_URL = "https://marketplace.visualstudio.com/items?itemName=diegosouzapw.omnicopilot";
+const MARKETPLACE_URL = "https://link.omniroute.online/vsx";
vi.mock("next-intl", () => ({ useTranslations: () => (k: string) => k }));