With GitHub sync, your page lives in a pageo.json file in a GitHub repository. Each push to the main branch updates your page. GitHub sync is free.
GitHub sync is not the GitHub contributions section. That section shows your contribution chart on your page, and you add it from the editor. GitHub sync replaces your page's content with a file from your repository.
Set up the repository
- On GitHub, create a public repository named
pageounder your own account, for examplegithub.com/yourname/pageo. - Add a
pageo.jsonfile at the root of themainbranch. To keep your current page, copy the file that the GitHub sync page shows under Start from your current page. Or start from the example below. - Set
emailin the file to the email address of your pageo account. pageo checks it, so only you can link the repository.
Link it to pageo
- In your pageo admin sidebar, under Account, choose GitHub sync.
- Enter your GitHub username and choose Check repository.
- Choose Link repository, then confirm. pageo reads
pageo.jsonfrom your latest commit onmain, and your page content is replaced with the file's content.
After you link, the GitHub sync page shows the repository, when it last synced, and the commit it synced from. Sync now reads the file again.
Update on every push
On the GitHub sync page, follow Update on every push:
- Copy the payload URL:
https://www.pageo.me/api/github/webhook - Choose Generate and copy, then Save secret.
- Open
github.com/yourname/pageo/settings/hooksand choose Add webhook. Paste the payload URL and the secret, set the content type toapplication/json, and choose Just the push event.
Pushes to other branches are ignored. The secret is optional, but without it pageo cannot confirm that a push came from GitHub.
Edits in the editor
Changes you save in the editor stay in pageo and do not reach GitHub. The next sync replaces them. To keep the two the same, copy the file under pageo.json on the GitHub sync page into your repository and commit it.
Unlink
Unlink GitHub at the bottom of the GitHub sync page stops syncing and resets your page to a clean default. The repository on GitHub is not changed.
Example pageo.json
{
"email": "you@example.com",
"profile": {
"name": "Maya Chen",
"role": "Product designer",
"bio": "I design calm software for small teams. **Booking for spring.**"
},
"socialLinks": [
{ "type": "github", "href": "https://github.com/mayachen" },
{ "type": "x", "href": "https://x.com/mayachen" },
{ "type": "linkedin", "href": "https://linkedin.com/in/mayachen" }
],
"gridLinks": [
{
"title": "Icon set",
"description": "120 calm interface icons",
"image": "https://example.com/icons.png",
"url": "https://mayachen.design/icons",
"layout": "grid",
"isPrimary": true
}
],
"settings": {
"layout": "grid",
"showContactForm": false
}
}
Field reference
Top level
| Field | Type | Required | Notes |
|---|---|---|---|
email | string | Yes | Must match your pageo account email. It is not shown on your page. |
profile | object | Yes | See below. |
socialLinks | array | Yes | Up to 12 items. Use [] for none. |
gridLinks | array | Yes | Any number of items. Use [] for none. |
settings | object | Yes | See below. |
profile
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | Yes | Your display name. |
role | string | Yes | The line under your name. |
bio | string | Yes | Markdown is supported. |
image | string | No | URL of your profile photo. |
email | string | No | A public contact email. |
socialLinks[]
| Field | Type | Required | Notes |
|---|---|---|---|
type | string | Yes | The icon, such as github, x, instagram, linkedin, youtube, or dribbble. |
href | string | Yes | The full URL. |
title | string | No | A label for the link. |
The order in the file is the order on your page.
gridLinks[]
| Field | Type | Required | Notes |
|---|---|---|---|
title | string | Yes | The card title. |
description | string | Yes | One line under the title. |
image | string | Yes | URL of the card image. |
url | string | Yes | Where the card links to. |
layout | grid, list, or minimal | Yes | The card style. |
isPrimary | boolean | No | Pins the card to lead your links. |
display | card or embed | No | embed shows a supported link as a player. See Players and embeds. |
kind | link, header, or text | No | header shows title as a section heading. text shows description as a note of up to 500 characters. Both ignore url and image, so set those to "". |
featured | boolean | No | Shows the link larger, across the full row. |
showFrom | string | No | An ISO time, such as 2026-11-01T09:00:00Z. The link shows from this time. pageo Pro. |
hideAfter | string | No | An ISO time. The link hides after this time. It must be after showFrom. pageo Pro. |
pageo numbers the links from their order in the file, so you never set id or order yourself.
settings
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
layout | list, grid, or minimal | Yes | The page layout. | |
showContactForm | boolean | Yes | Shows the contact form (pageo Pro). | |
allowAudienceSubscribe | boolean | No | false | Shows the subscribe button (pageo Pro). |
subscribeButtonLabel | string | No | Get updates | One of Get updates, Subscribe, Notify me, Stay updated. |
appendUtmParams | boolean | No | false | Adds UTM tags to outbound links. |
hideBranding | boolean | No | false | Hides the "Join <username> on pageo" badge (pageo Pro). |
profileMayContainNsfw | boolean | No | false | Shows a content warning before your page. |
seoTitle | string | No | Search result title (pageo Pro). | |
seoDescription | string | No | Search result description (pageo Pro). | |
mapEnabled | boolean | No | false | Shows the map section. |
mapLocation | string | No | City, State, Country, up to 100 characters. |
When a sync fails
pageo keeps your current page. When you link, the reason shows under the username on the GitHub sync page. For a push, open the webhook on GitHub and check Recent Deliveries:
- Repo or pageo.json not found: check the repository name (
pageo), the branch (main), and that the file sits at the root. - Not valid JSON: run the file through a JSON validator. A trailing comma is the usual cause.
- Does not match the required schema: compare the file with the reference above. Every required field must be present.
- Email does not match: set
emailto your pageo account email.