# SEO & AI Visibility

## SEO & AI Visibility

**Files:** `src/config/config.toml`, `src/i18n/<language>.json`, page frontmatter · **Skill level:** Beginner

Margo does the technical SEO for you: page titles and descriptions, canonical links, a sitemap, `robots.txt`, structured data, social preview cards, an RSS feed for the journal, and files for AI assistants. Your job is to set your address and identity, and to write good titles and descriptions.

### First, Set Your Address
```toml
[site]
  baseUrl = "https://www.your-domain.com"   # ships as "https://example.com"
```

Canonical links, the sitemap, `robots.txt`, RSS feeds, `llms.txt`, and social preview URLs all use it. Until you change it, `npm run build` prints a warning at the end. Don't deploy while you see it: every page would point search engines at `example.com`.

A `SITE_URL` environment variable on the build takes priority over `baseUrl`. On Vercel, the included `vercel.sh` sets one for you. `npm run generate-og-image` reads only `baseUrl`.

### Site Title, Tagline, And Description
```toml
[site]
  title            = "Margo"  # your name or studio name
  description      = "Editorial portfolio theme for designers, studios, and photographers, ..."
  tagline          = "Creative Portfolio Astro & Tailwind CSS Theme"
  taglineSeparator = ""       # default is " - "
```

Page titles get your tagline added: "About - Your tagline". `description` is the default meta description for pages that have none. A language can use its own tagline and description with `site.tagline` and `site.description` in `src/i18n/<language>.json`: French and Arabic ship with their own, so replace them too (see [Internationalization](/margo/customization/internationalization/)). Keep the tagline under about 55 characters.

```toml
[seo]
  author   = "Getastrothemes"  # put your own name or studio here
  keywords = ["portfolio astro theme", "..."] # default keywords for pages without their own
  robots   = "index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1"
```

Replace `author` and the sample `keywords` before launch. The `robots` value lets search and AI answers quote your pages and show their images in full.

### Who Runs The Site
```toml
[seo.identity]
  type     = "Organization" # Organization | Person
  name     = ""             # empty uses [site] title
  jobTitle = ""             # Person only, for example "Brand designer"
  image    = ""             # a logo (Organization) or a photo (Person)
```

Set `type = "Person"` if the site is one named designer or photographer, and `"Organization"` for a studio or business. Search engines read this as the publisher of the site, the creator of your projects, the provider of your services, and the author of journal posts that have no author of their own. An empty `image` uses `[site] logo`, and without a logo the theme's built-in mark. The profile links come from `src/config/social.json`: links to a bare domain such as `https://www.instagram.com` are skipped, so add your real profile addresses.

### Titles And Descriptions
Every page and entry accepts these frontmatter fields:

```yaml
---
title: "Brand identity"                              # shown on the page
metaTitle: "Brand identity for small companies"      # search result title (optional)
description: "Marks, type, and colour for..."        # page summary
metaDescription: "A brand identity built in..."      # 140–160 characters (optional)
image: "/images/services/brand-identity.jpg"         # social preview image (optional)
canonical: ""                                        # only if the page is a copy of another URL
robots: ""                                           # for example "noindex, follow"
keywords: ["brand identity", "logo design"]
disableTagline: false                                # true: no tagline after this page's title
---
```

### Structured Data (JSON-LD)
Margo writes structured data on every page from your content, so it matches what visitors see:

| Page | Structured data |
| --- | --- |
| Every page | The website and who runs it (`[seo.identity]`) |
| Project pages | A `CreativeWork` with the client, year, location, and categories |
| Service pages | A `Service` provided by you |
| Journal posts | A `BlogPosting` with the author from the author collection |
| Pages with breadcrumbs | A `BreadcrumbList` |
| `/faq/` | `FAQPage` with the questions on the page |

The FAQ markup is switched with `structuredData` in the FAQ block's options: `true` in `src/content/faq/<language>/-index.md`, and `false` on the pricing page and in the section defaults, so the same questions are marked up once. After launch, test a page with Google's [Rich Results Test](https://search.google.com/test/rich-results).

### Social Preview Cards
```toml
[opengraph]
  image          = "/images/og-image.jpg" # fallback image, public/images/og-image.jpg
  generateImages = true    # a 1200×630 card for every page without its own image
  theme          = "light" # light | dark
  twitter        = ""      # your X (Twitter) handle
```

- A page with its own `image` uses that image.
- Every other page gets a card generated during `npm run build`, with your logo, the section name, the page title, and the description, in your fonts and colours.
- Arabic pages use the fallback `image`, because the card generator can't lay out Arabic text.
- After you change your name, tagline, colours, or fonts (and after setting `baseUrl`), run `npm run generate-og-image` to redraw the fallback image in your branding.

### Sitemap, Robots, And Hidden Pages
- `/sitemap-index.xml` lists your pages. Leave a page out with `excludeFromSitemap: true`, or every page in a folder with `[seo.sitemap] exclude`. Draft pages are removed automatically.
- `/robots.txt` is built from `[seo.robotsTxt]`. Add paths crawlers must skip to `disallow`.
- `/elements/`, the layout gallery, ships hidden from search engines (`robots: "noindex, nofollow"`), out of the sitemap and out of site search. The 404 pages are `noindex` too.

### AI Search And AI Assistants
```toml
[seo.robotsTxt]
  aiSearch   = true # AI search and answer engines that fetch pages to cite them
  aiTraining = true # crawlers that collect content to train AI models
```

`aiSearch = false` asks AI answer engines to stay away; `aiTraining = false` opts out of training only. Neither affects Google Search or AI Overviews, which use the normal Googlebot. The crawler lists are in `src/lib/utils/aiCrawlers.ts`.

Margo also builds `/llms.txt`, `/llms-full.txt`, and a Markdown copy of your projects, services, journal posts, team members, and legal, pricing, and FAQ pages, and adds "Ask AI" links. All of that is explained in [AI Links & llms Files](/margo/features/ai-links-llms/).

### IndexNow (Bing And Others)
IndexNow tells Bing, Yandex, Seznam, and Naver which pages changed, so they update faster. It ships off.

<Steps>

1. Set a key of 8 to 128 letters, numbers, or dashes in `config.toml`: `indexNowKey = "your-key"` under `[seo.ai]`. The build publishes it at `/<key>.txt`.
2. Deploy.
3. After each deploy, run `npm run indexnow`. It sends the pages whose sitemap date changed in the last 7 days. `npm run indexnow -- --all` sends every page (use it at first launch), `--days=30` a longer period, and `--dry-run` lists the pages without sending them.

</Steps>

### Do It With AI
```text
Improve SEO for my portfolio. For every content file with a title in src/content/**/english/,
write a metaDescription of 140–160 characters from the page content, and a metaTitle under 60
characters where the title is vague. Don't change other fields. Then do the same in every other
language. Set [site] title, tagline, and description, [seo] author and keywords, and
[seo.identity] in src/config/config.toml for [MY NAME OR STUDIO, WHAT I DO, WHERE], update
site.tagline and site.description in src/i18n/fr.json and src/i18n/ar.json, and check that
[site] baseUrl is "[MY URL]".
```