Skip to content

Add comprehensive SEO: metadata, sitemap, robots, OG image, security headers#3

Merged
rowkav09 merged 2 commits into
mainfrom
copilot/add-seo-improvements
Mar 6, 2026
Merged

Add comprehensive SEO: metadata, sitemap, robots, OG image, security headers#3
rowkav09 merged 2 commits into
mainfrom
copilot/add-seo-improvements

Conversation

Copilot AI commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Improves discoverability of ghstats.dev by adding full Next.js SEO infrastructure and enriching the README with keyword-dense content.

App / metadata (src/app/)

  • layout.tsx — replaces minimal metadata with full SEO config: metadataBase, title template, 15-keyword array, openGraph/twitter card objects, alternates.canonical, robots directives, and JSON-LD WebApplication structured data injected via <script type="application/ld+json"> in <head>
  • sitemap.ts — dynamic MetadataRoute.Sitemap returning / (weekly, priority 1) and /api/card (daily, priority 0.8)
  • robots.ts — disallows crawling of /api/card, /api/badge, /api/visits (SVG endpoints); points to sitemap
  • opengraph-image.tsx — edge-rendered 1200×630 OG image via next/og ImageResponse; auto-routed by Next.js file convention, eliminating hardcoded image paths

Config (next.config.mjs)

Adds headers() applied to all routes:

X-DNS-Prefetch-Control: on
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin

README

Adds tagline, Why GitHub Profile Stats? bullet list, FAQ (targeting common search queries), Contributing, and Support sections. Existing badges and all prior content are untouched.

LICENSE

Adds MIT license file.

Original prompt

Overview

Add comprehensive SEO improvements to the rowkav09/GitHub-profile-stats repository to make it more visible on search engines (Google, Bing, etc.) and improve discoverability of the Vercel deployment at https://ghstats.dev.

IMPORTANT CONSTRAINTS

  • DO NOT modify or remove the existing badges at the top of the README. These two badge lines MUST remain exactly as they are:
    ![Users](https://ghstats.dev/api/badge)
    ![Visits](https://ghstats.dev/api/visits)
  • Keep the existing README content/structure intact — only add to it, don't remove existing content.

Changes Required

1. src/app/layout.tsx — Comprehensive Next.js Metadata

Replace the minimal metadata with a full SEO-optimized metadata export. The current file is:

import type { Metadata } from "next";
import { Analytics } from "@vercel/analytics/next";
import "./globals.css";

export const metadata: Metadata = {
  title: "GitHub Profile Stats",
  description:
    "Generate beautiful, embeddable GitHub stats cards for your README.",
  icons: {
    icon: "https://github.com/rowkav09.png",
  },
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className="bg-[#0d1117] text-[#c9d1d9] antialiased">
        {children}
        <Analytics />
      </body>
    </html>
  );
}

Update it to include:

  • metadataBase set to new URL("https://ghstats.dev")
  • title as an object with default: "GitHub Profile Stats — Beautiful Stats Cards for Your README" and template: "%s | GitHub Profile Stats"
  • A much longer keyword-rich description e.g.: "Generate beautiful, dynamically generated GitHub stats cards for your profile README. 13 stats, 12 themes, fully customizable SVG cards — just paste one line. No tokens, no setup, no deployment needed. Free and open source."
  • keywords array including: "github stats", "github profile stats", "github readme stats", "github stats card", "github profile readme", "readme stats generator", "github contribution stats", "github streak stats", "svg stats card", "developer stats", "github activity", "open source", "github readme generator", "profile readme", "github stats badge"
  • authors with name "rowkav09" and url "https://github.com/rowkav09"
  • creator: "rowkav09"
  • publisher: "rowkav09"
  • openGraph object with: title, description, url: "https://ghstats.dev", siteName: "GitHub Profile Stats", type: "website", locale: "en_US", and images array with one image: { url: "/og-image.png", width: 1200, height: 630, alt: "GitHub Profile Stats — Beautiful Stats Cards for Your README" }
  • twitter object with: card: "summary_large_image", title, description, images: ["/og-image.png"], creator: "@rowkav09"
  • alternates with canonical: "https://ghstats.dev"
  • robots with index: true, follow: true, googleBot: { index: true, follow: true, "max-video-preview": -1, "max-image-preview": "large", "max-snippet": -1 }
  • Keep the existing icons and Analytics component as-is.
  • Add JSON-LD structured data as a <script> tag inside the <head> section of the HTML. Use WebApplication schema with properties: name, description, url, applicationCategory: "DeveloperApplication", operatingSystem: "All", offers: { "@type": "Offer", "price": "0", "priceCurrency": "USD" }, and author info.

2. Create src/app/sitemap.ts

Create a dynamic sitemap file that exports a default function returning an array of sitemap entries:

import type { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://ghstats.dev",
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 1,
    },
    {
      url: "https://ghstats.dev/api/card",
      lastModified: new Date(),
      changeFrequency: "daily",
      priority: 0.8,
    },
  ];
}

3. Create src/app/robots.ts

Create a robots.txt generator:

import type { MetadataRoute } from "next";

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: "*",
        allow: "/",
        disallow: ["/api/card", "/api/badge", "/api/visits"],
      },
    ],
    sitemap: "https://ghstats.dev/sitemap.xml",
  };
}

The /api/card, /api/badge, and /api/visits routes should be disallowed since they return SVGs/images, not HTML pages.

4. Create public/og-image.png

Since we can't easily generate an image file in the PR, instead create src/app/opengraph-image.tsx using Next.js ImageResponse from next/og:

import { ImageResponse } from "next/og";

export const runtime = "edge";
export const alt = "GitHub Profile Stats — Beautiful Stats Cards for Your README";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";

export default async function Image() {
...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

@vercel

vercel Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
git-stats Ready Ready Preview, Comment Mar 6, 2026 4:48pm

…ge, headers, README, LICENSE

Co-authored-by: rowkav09 <230578460+rowkav09@users.noreply.github.com>
Copilot AI changed the title [WIP] Add comprehensive SEO improvements for visibility Add comprehensive SEO: metadata, sitemap, robots, OG image, security headers Mar 6, 2026
@rowkav09

rowkav09 commented Mar 6, 2026

Copy link
Copy Markdown
Owner

@copilot is it ready?

Copilot AI commented Mar 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot is it ready?

Yes, all changes are in and the build passes with zero TypeScript errors and no CodeQL alerts. Here's what's included:

  • src/app/layout.tsx — full SEO metadata (title template, keywords, openGraph, Twitter cards, canonical, robots) + JSON-LD WebApplication structured data
  • src/app/sitemap.ts — dynamic sitemap at /sitemap.xml
  • src/app/robots.ts — robots.txt disallowing the SVG API routes
  • src/app/opengraph-image.tsx — edge-rendered 1200×630 OG image
  • next.config.mjs — security/SEO headers (X-Frame-Options, X-Content-Type-Options, Referrer-Policy, X-DNS-Prefetch-Control)
  • README.md — tagline, "Why GitHub Profile Stats?", FAQ, Contributing, and Support sections added (existing badges untouched)
  • LICENSE — MIT license file

Ready to merge whenever you are.

@rowkav09

rowkav09 commented Mar 6, 2026

Copy link
Copy Markdown
Owner

@copilot Let's merge

Copilot AI commented Mar 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot Let's merge

I'm not able to merge pull requests directly — you'll need to click the Merge pull request button on the GitHub PR page to complete the merge.

@rowkav09
rowkav09 marked this pull request as ready for review March 6, 2026 17:05
@rowkav09
rowkav09 requested review from Copilot and removed request for Copilot March 6, 2026 17:05
@rowkav09
rowkav09 merged commit ce232da into main Mar 6, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants