# Config Reference (config.toml)

## Config Reference

**File:** `src/config/config.toml` · **Skill level:** Beginner

`config.toml` holds every site-wide setting: your site name and address, search engine settings, the header and footer layouts, the forms, the animations, and more. It is grouped into tables: a line in `[brackets]` starts a table, and every `key = value` line below it belongs to that table until the next one. Most keys have a comment beside them; this page explains them all in one place, with the value Margo ships.

Values marked `PLACEHOLDER` in the file must be replaced before you launch.

<Aside type="note">
  `npm run dev` picks up a saved change to `config.toml` and reloads the page.
  Restart it after you change `trailingSlash`, anything in
  `[settings.multilingual]`, or `src/config/fonts.json`: those are read only
  when the server starts.
</Aside>

### Site Identity
Table: `[site]`

| Key                | Ships as                 | What it does                                                                                   |
| ------------------ | ------------------------ | ---------------------------------------------------------------------------------------------- |
| `title`            | `"Margo"`                | Site name. The wordmark when `logoText` and `logo` are empty, `{brand}` in the footer copyright, the site name in social previews and structured data, and the RSS feed title |
| `description`      | a sentence about the theme | Default description for search results and social previews. A language with `site.description` set in `src/i18n/<lang>.json` uses that instead |
| `tagline`          | `"Creative Portfolio Astro & Tailwind CSS Theme"` | Added to every page title ("About - your tagline") and social titles. Keep it under about 55 characters. A language with `site.tagline` set in `src/i18n/<lang>.json` uses that instead (French and Arabic do). A page turns it off with `disableTagline: true` |
| `taglineSeparator` | `""`                     | Text between page title and tagline. Empty uses `" - "`                                        |
| `baseUrl`          | `"https://example.com"`  | **Placeholder.** Your live address. Canonical links, the sitemap, `robots.txt`, RSS feeds, `llms.txt`, and social URLs are built from it, and `npm run build` warns while it is `example.com`. A `SITE_URL` environment variable on the build overrides it |
| `logo`             | `""`                     | Path to a logo image (SVG or PNG). Empty shows `logoText` as a text wordmark                   |
| `logoText`         | `"Margo"`                | The wordmark text. With a `logo` image it shows next to it; empty shows the image only         |
| `logoWidth`, `logoHeight` | `"24px"`, `"36px"` | Logo image size. Used only when `logo` is set                                                 |
| `trailingSlash`    | `true`                   | URLs end with `/` (`/about/`). Restart the dev server after a change                           |
| `[site.favicon] path`  | `"/images/favicons"` | Where the generated favicons go. Leave it as it is                                             |
| `[site.favicon] image` | `"/images/favicon.svg"` | Source image for `npm run generate-favicons` (`src/assets/images/favicon.svg`)              |

Details: [Site Identity & Logo](/margo/customization/site-identity-logo/).

### Search Engines
Tables: `[seo]`, `[seo.identity]`, `[seo.robotsTxt]`, `[seo.ai]`, `[seo.sitemap]`

| Key                          | Ships as  | What it does                                                                                 |
| ---------------------------- | --------- | -------------------------------------------------------------------------------------------- |
| `author`                     | `"Getastrothemes"` | Default author meta tag. Put your own name or studio here                           |
| `keywords`                   | eight portfolio keywords | Default keywords for pages without their own `keywords`                               |
| `robots`                     | `"index, follow, max-snippet:-1, ..."` | Default robots meta tag. Lets search and AI answers quote pages and show images in full |
| `[seo.identity] type`        | `"Organization"` | `Organization` for a studio or business, `Person` for one named designer or photographer. Used in the structured data on every page |
| `[seo.identity] name`        | `""`      | Who runs the site. Empty uses `[site] title`                                                 |
| `[seo.identity] jobTitle`    | `""`      | `Person` only, for example `"Brand designer"`                                                |
| `[seo.identity] image`       | `""`      | A logo for an organization or a photo for a person. Empty uses `[site] logo`, else the built-in mark |
| `[seo.robotsTxt] enable`     | `true`    | Builds `/robots.txt`                                                                          |
| `[seo.robotsTxt] disallow`   | `[]`      | Paths crawlers must skip                                                                      |
| `[seo.robotsTxt] aiSearch`   | `true`    | `false` asks AI answer engines (ChatGPT search, Claude, Perplexity, and others) not to fetch your pages |
| `[seo.robotsTxt] aiTraining` | `true`    | `false` asks crawlers that collect content to train AI models to stay away                   |
| `[seo.ai] llmsTxt`           | `true`    | Builds `/llms.txt` and `/llms-full.txt`, one per language                                     |
| `[seo.ai] markdownPages`     | `true`    | A Markdown copy of each project, service, journal post, team member, legal page, and the pricing and FAQ pages at `<page>.md` |
| `[seo.ai] indexNowKey`       | `""`      | An 8 to 128 character key turns on IndexNow; run `npm run indexnow` after each deploy        |
| `[seo.sitemap] enable`       | `true`    | Builds the sitemap                                                                            |
| `[seo.sitemap] exclude`      | `[]`      | Folder names to leave out of the sitemap                                                      |

Details: [SEO & AI Visibility](/margo/customization/seo-ai-visibility/) and [AI Links & llms Files](/margo/features/ai-links-llms/).

### General Settings
Table: `[settings]`

| Key                   | Ships as                 | What it does                                                                     |
| --------------------- | ------------------------ | -------------------------------------------------------------------------------- |
| `blogFolder`          | `"blog"`                 | Folder name of the journal. Changing it also means renaming the folders in `src/content/` and `src/pages/[...lang]/` and the collection in `src/content.config.ts`. Most sites keep it |
| `servicesFolder`      | `"services"`             | The same, for services                                                           |
| `projectsFolder`      | `"projects"`             | The same, for projects (case studies and photo series)                           |
| `blogPagination`      | `6`                      | Posts per journal list page                                                      |
| `pagination`          | `8`                      | Used for the journal only when `blogPagination` is empty                         |
| `stickyHeader`        | `true`                   | Kept for older themes. Margo's header always stays at the top of the screen, so this key changes nothing |
| `colorMode`           | `"light"`                | Light or dark mode on a visitor's first visit: `light`, `dark`, or `system` (follows the device). See [Colors & Fonts](/margo/customization/colors-fonts/#light-and-dark-mode) |
| `contactFormAction`   | `"https://formsubmit.co/your-email@example.com"` | **Placeholder.** Where the contact form sends its data. `npm run dev` and `build` warn until you change it |
| `contactFormProvider` | `"formsubmit.co"`        | `"formsubmit.co"`, `"formspree"`, or `"netlify"`                                 |

Details: [Forms](/margo/customization/forms/).

### Header, Footer, And Page Background
Table: `[settings.layout]`

| Key      | Ships as   | What it does                                    |
| -------- | ---------- | ----------------------------------------------- |
| `header` | `"bar"`    | `pill`, `bar`, or `overlay`                     |
| `footer` | `"email"`  | `wordmark`, `columns`, or `email`               |
| `frame`  | `true`     | Thin ruled lines at the edges of the content and at the top of sections. `false` removes them |
| `aurora` | `true`     | Soft color fields behind every page. `false` leaves a plain background |

A page's `headerLayout` or `footerLayout` frontmatter wins over `header` and `footer`. See [Header](/margo/customization/header/), [Footer](/margo/customization/footer/), and [Colors & Fonts](/margo/customization/colors-fonts/#frame-and-aurora).

### Search
Table: `[settings.search]`

| Key       | Ships as           | What it does                                                                    |
| --------- | ------------------ | ------------------------------------------------------------------------------- |
| `enable`  | `true`             | The site search window (<kbd>Cmd</kbd> + <kbd>K</kbd>, <kbd>Ctrl</kbd> + <kbd>K</kbd>, or <kbd>/</kbd>) |
| `exclude` | `["/components/"]` | Address prefixes left out of the search index                                   |

The index is built at the end of `npm run build`, so search works on the built site, not in `npm run dev`. Details: [Search](/margo/customization/search/).

### Smooth Scroll
Table: `[settings.smoothScroll]`

Smooth scrolling for mouse and trackpad, powered by Lenis. Touch screens keep their normal scrolling.

| Key                     | Ships as | What it does                                                    |
| ----------------------- | -------- | --------------------------------------------------------------- |
| `enable`                | `true`   | `false` gives you the browser's normal scrolling                |
| `respectReducedMotion`  | `true`   | Keeps it off for visitors who ask for less motion               |
| `duration`              | `1.0`    | How long the glide lasts. Higher feels slower                   |
| `easing`                | `"expo"` | `expo`, `linear`, `easeOutQuad`, or `easeOutCubic`              |
| `smoothWheel`           | `true`   | Smooths mouse wheel and trackpad scrolling                      |
| `syncTouch`             | `false`  | Smooths touch input on devices with a mouse and a touchscreen   |
| `wheelMultiplier`       | `1`      | How far one wheel movement scrolls                              |
| `touchMultiplier`       | `1`      | How far one swipe scrolls when `syncTouch` is on                |
| `anchors`               | `true`   | Glides to `#section` links, offset by the header height         |
| `autoRaf`               | `false`  | No effect: the theme always drives Lenis from its own animation loop |
| `stopInertiaOnNavigate` | `true`   | Stops any remaining glide when a visitor clicks a link          |

Details: [Smooth Scroll](/margo/features/smooth-scroll/).

### Cookie Banner
Table: `[settings.cookieConsent]`

| Key        | Ships as | What it does                                                                  |
| ---------- | -------- | ----------------------------------------------------------------------------- |
| `enable`   | `true`   | Shows the cookie banner and holds `data-consent` scripts until visitors choose |
| `revision` | `1`      | Raise it by 1 when your cookie use changes, to ask every visitor again       |

The banner's copy is in `src/content/sections/english/cookie-consent.md` (and each other language folder). If you turn the banner off, also set `enable` to `false` on the "Cookie settings" item in the Legal column of the footer menus. Details: [Cookies & Analytics](/margo/customization/cookies-analytics/).

### Theme Credit
Table: `[settings.themeCredit]`

The theme credit, editable in `config.toml`. It is one small line in every footer layout and the last line of `llms.txt`. The part of `text` in `[brackets]` becomes the link to `url`.

```toml
[settings.themeCredit]
  enable = true
  text   = "Built on the Margo Astro theme by [Getastrothemes]"
  url    = "https://getastrothemes.com/astro-themes/margo/"
```

### Page Actions And AI Links
Table: `[settings.pageActions]`

| Key         | Ships as | What it does                                                                                  |
| ----------- | -------- | --------------------------------------------------------------------------------------------- |
| `enable`    | `true`   | The **Copy page** menu at the end of each journal post: copy the post as Markdown, open the Markdown copy, or ask an assistant about it. Copy and **View as Markdown** need `[seo.ai] markdownPages` |
| `footer`    | `true`   | A row at the bottom of every footer layout with Ask AI links, the page in Markdown, `llms.txt`, and `llms-full.txt` |
| `providers` | `["chatgpt", "claude", "perplexity", "grok"]` | Assistants offered in "Ask". Empty hides the "Ask" links             |

See [AI Links & llms Files](/margo/features/ai-links-llms/).

### Animations
Table: `[settings.animation]`

With `enable = false`, or for visitors who ask for less motion, every page is static and fully visible.

| Key                    | Ships as     | What it does                                                         |
| ---------------------- | ------------ | -------------------------------------------------------------------- |
| `enable`               | `true`       | Turns every animation on or off                                      |
| `respectReducedMotion` | `true`       | Shows content without animation for visitors who ask for less motion |
| `intro`                | `true`       | The hero and page header headline animate in when the page opens     |
| `reveal`               | `true`       | Content fades and rises in on scroll, headings blur in word by word, numbers count up |
| `scroll`               | `true`       | Effects tied to scrolling: parallax, text and images that move with the scroll, the hero card flight |
| `webgl`                | `true`       | Animated backgrounds on the surfaces that ask for one (`options.webgl`). `false` keeps the still dots |
| `mobile`               | `"lite"`     | Below 768 px: `full`, `lite` (reveals, counters, and moving rows, no scroll effects), or `off` |
| `pageTransitions`      | `true`       | A fade between pages, and the project image moving into the project page (Chrome, Safari 18.2 and later) |
| `easing`               | `"expo"`     | `expo`, `quart`, `cubic`, or any CSS timing function                 |
| `duration`             | `0.9`        | Reveal duration, in seconds                                          |
| `stagger`              | `0.08`       | Delay between items of a group, in seconds                           |
| `distance`             | `"1.25rem"`  | How far content rises while fading in                                |
| `rootMargin`, `threshold` | `"0px 0px -10% 0px"`, `0.15` | How early an element starts animating          |

Details: [Animations](/margo/customization/animations/).

### Pointer Label, Contact Dock, And Edge Blur
Tables: `[settings.cursor]`, `[settings.contactDock]`, `[settings.edgeBlur]`

| Key                         | Ships as          | What it does                                                         |
| --------------------------- | ----------------- | -------------------------------------------------------------------- |
| `[settings.cursor] enable`  | `true`            | A small "View" or "Read" label follows the pointer over project and journal cards (mouse and trackpad only) |
| `[settings.contactDock] enable` | `false`       | A small bar at the bottom of the screen with an availability line, **Copy email**, and **Book a call**. A page turns it on or off with `contactDock: true` or `false` in its frontmatter |
| `[settings.contactDock] showAfter` | `"first-section"` | The dock slides in once the first section of the page has scrolled away |
| `[settings.edgeBlur] enable` | `false`          | A soft blur along the bottom edge of the screen, on large screens with a mouse. Check that pages still scroll smoothly on a slower computer if you turn it on |

The dock's email and booking link come from `[settings.contactInfo]`. Details: [Animations](/margo/customization/animations/) and [Contact & Booking](/margo/customization/contact-booking/).

### Layout Switcher
Table: `[settings.layoutSwitcher]`

Keep `enable = false` on your own site. To change how a section looks, set `options.layout`: see [Section Layouts](/margo/customization/section-layouts/).

### Copyright
Table: `[settings.copyright]`

`enable` (`true`) shows the copyright line in the footer. `text` (`""`) overrides `footer.copyright` from the i18n files for every language. In both, `{year}` becomes the year of the build and `{brand}` the `site.title`.

### Newsletter
Table: `[settings.subscription]`

The Mailchimp signup used by the newsletter section on the journal and by the `columns` footer.

| Key                 | Ships as          | What it does                                                                   |
| ------------------- | ----------------- | ------------------------------------------------------------------------------ |
| `enable`            | `true`            | `false` hides every signup form                                                |
| `title`             | `""`              | Empty uses `subscription.title` from the i18n files                            |
| `note`              | `""`              | The line under the field. Empty uses `subscription.note`                       |
| `formAction`        | a placeholder URL | **Placeholder.** Your Mailchimp embedded form action. Change each `&amp;` in the copied URL to `&`. `npm run dev` shows a warning inside each form until it is set |
| `mailchimpTagValue` | `""`              | Optional Mailchimp tag id added to every signup                                |

### Languages
Table: `[settings.multilingual]`

| Key                    | Ships as | What it does                                                          |
| ---------------------- | -------- | --------------------------------------------------------------------- |
| `enable`               | `true`   | `false` builds only the default language. Then run `npm run remove-multilingual` to delete the files of every other language |
| `defaultLanguage`      | `"en"`   | Language served without a prefix                                     |
| `disableLanguages`     | `[""]`   | Languages to skip, for example `["ar"]`                              |
| `showDefaultLangInUrl` | `false`  | `true` adds the prefix to the default language too (`/en/about/`)    |

Restart the dev server after any change here. Details: [Internationalization](/margo/customization/internationalization/).

### Contact Details
Table: `[settings.contactInfo]`

| Key           | Ships as                          | What it does                                                    |
| ------------- | --------------------------------- | --------------------------------------------------------------- |
| `email`       | `"[hello@example.com](mailto:hello@example.com)"` | **Placeholder.** Used by the **Copy email** buttons of the contact dock and the mobile menu, and listed in `llms.txt` |
| `booking`     | `"/contact/"`                     | Where every **Book a call** button goes: the contact dock, the FAQ card, the call to action, and the booking card on the contact page. Use your scheduling page (a full `https://` address) or a page of your site |
| `phone`       | a sample number                   | Listed in `llms.txt`. Not shown on the pages                    |
| `address`     | a sample address                  | Listed in `llms.txt`. Not shown on the pages                    |
| `officeHours` | sample hours                      | Not shown by the theme's layouts                                |

The email, phone, location, and social rows beside the contact form are in `src/content/sections/<language>/contact-section.md`, so they can differ per language. See [Contact & Booking](/margo/customization/contact-booking/).

### Header Button
Table: `[settings.navigationButton]`

| Key      | Ships as      | What it does                                                                 |
| -------- | ------------- | ---------------------------------------------------------------------------- |
| `enable` | `true`        | Shows the button at the end of the header and in the mobile menu             |
| `label`  | `""`          | Empty uses `nav.letsTalk` from the i18n files ("Let's talk"). A value here is used in every language |
| `url`    | `"/contact/"` | Where it goes                                                                |

### Code Blocks And Tables Of Contents
Tables: `[settings.markup.codeBlocks]`, `[settings.markup.tableOfContents]`

- `[settings.markup.codeBlocks] theme`: `auto` (follows light and dark mode, the default) or `dark` (dark code blocks in both modes), for fenced code in Markdown and MDX.
- `[settings.markup.tableOfContents]`: the "On this page" list on journal posts and text pages such as the privacy policy. It ships with `enable = true`, `expanded = false`, `startLevel = 1`, `endLevel = 5`, and `ordered = false`.

### Social Previews
Table: `[opengraph]`

| Key              | Ships as                    | What it does                                                         |
| ---------------- | --------------------------- | -------------------------------------------------------------------- |
| `image`          | `"/images/og-image.jpg"`    | Shared preview image (`public/images/og-image.jpg`), used when a page has no `image` and no generated card |
| `generateImages` | `true`                      | During `npm run build`, draws a 1200×630 card for every page without an `image` |
| `theme`          | `"light"`                   | `light` or `dark` palette for the generated cards and `npm run generate-og-image` |
| `ogLocale`       | `"en_US"`                   | Fallback locale. Each language sets its own `ogLocale` in `src/config/language.json` |
| `ogType`         | `"website"`                 | Open Graph type                                                      |
| `twitter`, `twitterCard` | `""`, `"summary_large_image"` | X (Twitter) handle and card type                             |

Details: [Site Identity & Logo](/margo/customization/site-identity-logo/#social-preview-images).

### Custom Head Scripts
Table: `[head]`

`content` is pasted into the `<head>` of every page. Use it for analytics, verification tags, or extra stylesheets. With the cookie banner on, change each tracking `<script>` to `<script type="text/plain" data-consent="analytics">` (or `"marketing"`) so it waits for consent; the comment above `[head]` shows an example. See [Cookies & Analytics](/margo/customization/cookies-analytics/).

### The Other Files In `src/config/`
| File                              | What it holds                                                                        | Page                                                        |
| --------------------------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------- |
| `menu.<language>.json`            | The header menu (`headerPrimary`) and the footer link columns (`footer`)             | [Menus](/margo/customization/menus/)                        |
| `language.json`                   | The languages: name, code, content folder, direction, `ogLocale`, `dateLocale`, and order | [Internationalization](/margo/customization/internationalization/) |
| `fonts.json`                      | The fonts: text, the serif accent, and Arabic                                        | [Colors & Fonts](/margo/customization/colors-fonts/#fonts)  |
| `social.json`                     | Social links and their icons (`main` list)                                           | [Footer](/margo/customization/footer/#social-links)         |

Colors are not in `src/config/`: they are tokens in `src/styles/theme.css`.

### Do It With AI
```text
Explain each table of src/config/config.toml in one line, then list every value marked
"PLACEHOLDER" or still using example.com, and the current value of each. Don't change anything
yet.
```