Menu

Video links Link pages Presentations AI assistant Pricing Docs Deutsch
Sign in

Accounts are invite-only while I finish onboarding — write to email.

Link pages

Build a link page at yourname.cvinfo.me from a simple form or JSON — themes, links, info blocks and analytics.

A link page lives at https://yourname.cvinfo.me/ and costs 2 credits once. Editing and republishing are free.

Create one#

  1. Pages & decks → Link page, choose the address (yourname) and create it.
  2. Fill in the editor: name, headline, location, email, photo URL, theme, bio, links and info blocks.
  3. Watch the live preview, then press Save & publish.

The address can't be changed later; everything else can.

Fields#

Field Notes
Name Required, the page heading
Headline One line, e.g. "Senior data engineer"
Photo URL Must be https://
Bio Markdown
Links One per line in the editor: Label | https://…. Icons are picked from the URL
Info blocks Markdown; each ## Title starts a new block
Theme cvinfo, midnight, light or sunset

Show in search engines#

New pages are hidden from Google (noindex). Switch on Show in search engines in the editor if you want the page to be found. Links on your page carry rel="ugc nofollow".

Versions and rollback#

Every publish creates a version. On Pages & decks you can roll back to any of the last five.

Create a tracked link per application (1 credit) to see which company opened your page.

JSON spec#

Behind the editor (and the AI assistant) every page is this JSON:

{
  "name": "Jane Doe",
  "headline": "Senior data engineer · Python, Spark, dbt",
  "location": "Berlin",
  "email": "jane@example.com",
  "avatar_url": "https://example.com/jane.jpg",
  "bio": "I build **reliable data platforms**. Currently open to new roles.",
  "theme": "cvinfo",
  "links": [
    {
      "label": "LinkedIn",
      "url": "https://linkedin.com/in/janedoe",
      "icon": "linkedin"
    },
    {
      "label": "GitHub",
      "url": "https://github.com/janedoe",
      "icon": "github"
    },
    {
      "label": "Download my CV",
      "url": "https://example.com/cv.pdf",
      "icon": "cv"
    }
  ],
  "sections": [
    {
      "title": "Experience",
      "markdown": "- **Acme** — Lead data engineer (2021–)\n- **Initech** — Data engineer (2018–2021)"
    }
  ],
  "video": {
    "source": "video:0b6e1e8a-6f0e-4a3c-9d2d-2f9c8a1b4d77",
    "caption": "60 seconds on why this role"
  },
  "deck": {
    "slug": "jane-talk",
    "label": "My fraud-scoring project"
  },
  "references": [
    {
      "name": "Ada Fischer",
      "role": "CTO",
      "company": "Acme GmbH",
      "contact": "ada@acme.example",
      "quote": "Jane turned our data swamp into a platform."
    }
  ],
  "gate": {
    "enabled": true,
    "title": "Enter your work email to unlock"
  }
}
Full JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "cvinfo structured page",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80,
      "description": "Display name, the page heading."
    },
    "headline": {
      "type": "string",
      "maxLength": 140,
      "description": "One line under the name, e.g. 'Senior data engineer'."
    },
    "location": {
      "type": "string",
      "maxLength": 80
    },
    "email": {
      "type": "string",
      "maxLength": 254,
      "format": "email",
      "description": "Shown as a mailto button."
    },
    "avatar_url": {
      "type": "string",
      "maxLength": 500,
      "pattern": "^https://\\S+$",
      "description": "https URL of a square photo."
    },
    "avatar_file": {
      "type": "string",
      "maxLength": 40,
      "pattern": "^avatar-[0-9a-f]{8}\\.jpg$",
      "description": "Read-only: a photo uploaded in the editor, served from the page's own host. Set by the app, not by API clients."
    },
    "bio": {
      "type": "string",
      "maxLength": 3000,
      "description": "Markdown."
    },
    "theme": {
      "enum": [
        "midnight",
        "light",
        "cvinfo",
        "sunset"
      ],
      "default": "cvinfo"
    },
    "links": {
      "type": "array",
      "maxItems": 30,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "label",
          "url"
        ],
        "properties": {
          "label": {
            "type": "string",
            "minLength": 1,
            "maxLength": 60
          },
          "url": {
            "type": "string",
            "maxLength": 500,
            "pattern": "^(https?://|mailto:)\\S+$"
          },
          "icon": {
            "enum": [
              "link",
              "linkedin",
              "github",
              "gitlab",
              "x",
              "mastodon",
              "bluesky",
              "youtube",
              "instagram",
              "website",
              "email",
              "cv",
              "calendar",
              "phone",
              "portfolio",
              "blog"
            ]
          }
        }
      }
    },
    "sections": {
      "type": "array",
      "maxItems": 12,
      "description": "Info blocks under the links (experience, skills, projects\u2026).",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "title",
          "markdown"
        ],
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "markdown": {
            "type": "string",
            "maxLength": 6000
          }
        }
      }
    },
    "video": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "source"
      ],
      "description": "An intro video at the top of the page: 'video:<id>' picks one from your video library. Upload and review happen in the app (cvinfo.me/videos/), which is also where each video's id is shown. The page streams it from cvinfo.me through an expiring URL, and only while it is approved. 'profile' and 'link:<uuid>' are still understood \u2014 they are what specs said before videos became reusable.",
      "properties": {
        "source": {
          "type": "string",
          "maxLength": 80,
          "pattern": "^(profile|link:[0-9a-f-]{36}|video:[0-9a-f-]{36})$"
        },
        "caption": {
          "type": "string",
          "maxLength": 140
        }
      }
    },
    "deck": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "slug"
      ],
      "description": "One of your own presentations, shown as a card that opens it.",
      "properties": {
        "slug": {
          "type": "string",
          "maxLength": 63,
          "pattern": "^[a-z0-9-]+$"
        },
        "label": {
          "type": "string",
          "maxLength": 80
        }
      }
    },
    "references": {
      "type": "array",
      "maxItems": 8,
      "description": "People who vouch for you. Hidden behind the e-mail gate when it is on.",
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          },
          "role": {
            "type": "string",
            "maxLength": 120
          },
          "company": {
            "type": "string",
            "maxLength": 80
          },
          "contact": {
            "type": "string",
            "maxLength": 254
          },
          "quote": {
            "type": "string",
            "maxLength": 400
          }
        }
      }
    },
    "css": {
      "type": "string",
      "maxLength": 50000,
      "description": "Custom CSS theme, applied after the built-in theme. Sanitised: no @import, no external url() \u2014 only uploaded images as url(upload:<id>)."
    },
    "gate": {
      "type": "object",
      "additionalProperties": false,
      "description": "Ask visitors for a work e-mail before the references are shown.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": false
        },
        "title": {
          "type": "string",
          "maxLength": 120
        }
      }
    }
  }
}