From d37535302890790a67b3916a6b6015e4f90db87c Mon Sep 17 00:00:00 2001 From: RISHII <93994298+RISHII7@users.noreply.github.com> Date: Thu, 9 Jul 2026 12:59:34 +0530 Subject: [PATCH] feat(web): add Open Graph & Twitter link previews MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shared links to the web app previewed as "404: This page could not be found" because the root redirects into the auth-gated dashboard, so crawlers never saw real metadata. - Add metadataBase, openGraph, and twitter metadata to the root layout - Generate a branded 1200x630 preview card via next/og (opengraph-image.tsx, re-exported as twitter-image.tsx) — no static asset to maintain - Make /opengraph-image and /twitter-image public in proxy.ts so crawlers can fetch the image without authentication Public pages (e.g. /sign-in) now render a proper social card. --- CHANGELOG.md | 13 +++++ apps/web/app/layout.tsx | 25 +++++++- apps/web/app/opengraph-image.tsx | 98 ++++++++++++++++++++++++++++++++ apps/web/app/twitter-image.tsx | 3 + apps/web/proxy.ts | 10 +++- 5 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 apps/web/app/opengraph-image.tsx create mode 100644 apps/web/app/twitter-image.tsx diff --git a/CHANGELOG.md b/CHANGELOG.md index b3aa45e..a86cd8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +#### Open Graph & Twitter link previews + +- Added `metadataBase`, `openGraph`, and `twitter` metadata to the web app's + root layout so shared links render a proper social card instead of the + auth-gated app's "404: This page could not be found." +- Added `apps/web/app/opengraph-image.tsx` (and a re-exporting + `twitter-image.tsx`) that generate a branded 1200×630 preview card at + build/request time via `next/og` — no static asset to maintain. +- Marked `/opengraph-image` and `/twitter-image` as public routes in + `proxy.ts` so crawlers can fetch the preview image without authentication. + ### Changed #### Production widget URL & dashboard entry point diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index 302f315..642363c 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -16,13 +16,20 @@ const fontMono = Geist_Mono({ variable: "--font-mono", }) +const siteUrl = + process.env.NEXT_PUBLIC_APP_URL ?? "https://echo-red-kappa.vercel.app" + +const siteTitle = "Echo — AI-Powered Customer Support Platform" +const siteDescription = + "Echo is a B2B AI-powered customer support platform. Deploy an embeddable chat and voice widget, resolve conversations with an AI agent grounded in your knowledge base, and manage everything from a real-time operator dashboard." + export const metadata: Metadata = { + metadataBase: new URL(siteUrl), title: { - default: "Echo — AI-Powered Customer Support Platform", + default: siteTitle, template: "%s · Echo", }, - description: - "Echo is a B2B AI-powered customer support platform. Deploy an embeddable chat and voice widget, resolve conversations with an AI agent grounded in your knowledge base, and manage everything from a real-time operator dashboard.", + description: siteDescription, applicationName: "Echo", keywords: [ "AI customer support", @@ -35,6 +42,18 @@ export const metadata: Metadata = { icons: { icon: "/icon.svg", }, + openGraph: { + type: "website", + url: siteUrl, + siteName: "Echo", + title: siteTitle, + description: siteDescription, + }, + twitter: { + card: "summary_large_image", + title: siteTitle, + description: siteDescription, + }, } export default function RootLayout({ diff --git a/apps/web/app/opengraph-image.tsx b/apps/web/app/opengraph-image.tsx new file mode 100644 index 0000000..7697ea3 --- /dev/null +++ b/apps/web/app/opengraph-image.tsx @@ -0,0 +1,98 @@ +import { ImageResponse } from "next/og" + +// Route segment config +export const alt = "Echo — AI-Powered Customer Support Platform" +export const size = { width: 1200, height: 630 } +export const contentType = "image/png" + +// Branded Open Graph card, generated at build/request time so shared links +// (LinkedIn, X, Slack, etc.) always render a proper preview instead of the +// auth-gated app's 404. +export default function OpengraphImage() { + return new ImageResponse( +