GitHub Pages

GitHub Pages cannot run server code. Add a working contact form to a GitHub Pages site with one HTML form and no backend.

GitHub Pages is a static host: it serves the HTML, CSS and JavaScript files in your repository and nothing else. There is no PHP, no server-side code and no form handling, so a form whose action points at your own site has nothing to receive it. The fix is to post the form somewhere else. With SilentForms the visitor's browser sends the form straight to the submit endpoint, and the submission is emailed to you. Your repository only ever contains static files.

1. Get an access key#

Enter your email on the access key page and click the confirmation link. The key is safe to commit to a public repository: it only routes submissions to your inbox and cannot read anything.

2. Add the form#

Create contact.html in the folder GitHub Pages publishes from (the repository root, /docs, or your build output). This page needs no build step or framework:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Contact</title>
</head>
<body>
  <h1>Contact</h1>
  <form action="https://silentforms.com/api/submit" method="POST">
    <input type="hidden" name="accessKey" value="YOUR_ACCESS_KEY_HERE">
    <input type="hidden" name="redirect" value="https://username.github.io/my-repo/thanks.html">

    <label for="name">Name</label>
    <input id="name" type="text" name="name" autocomplete="name" required>

    <label for="email">Email</label>
    <input id="email" type="email" name="email" autocomplete="email" required>

    <label for="message">Message</label>
    <textarea id="message" name="message" rows="6" required></textarea>

    <!-- Honeypot: hidden from people, filled in by bots -->
    <input type="checkbox" name="botcheck" style="display: none;" tabindex="-1" autocomplete="off">

    <button type="submit">Send</button>
  </form>
</body>
</html>

Replace the key and the redirect URL. The redirect must be a full https:// URL, and its shape depends on the kind of site:

  • User or organisation site (repository named username.github.io): https://username.github.io/thanks.html.
  • Project site (any other repository): https://username.github.io/my-repo/thanks.html. The repository name is part of every URL, and forgetting it is the most common reason the redirect ends on a GitHub 404 page.
  • Custom domain: https://www.example.com/thanks.html.

3. Add the thank-you page#

Create thanks.html next to contact.html, in the same repository:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex">
  <title>Thanks</title>
</head>
<body>
  <h1>Thanks!</h1>
  <p>Your message is on its way. We will reply by email.</p>
  <p><a href="./">Back to the homepage</a></p>
</body>
</html>

If you leave out the redirect field, visitors land on the default SilentForms success page instead. See Redirect after submit.

4. Publish and test#

Commit both files and push. In the repository, Settings then Pages shows the publishing source (a branch or GitHub Actions) and the live URL once the deployment finishes. Open /contact.html on that URL, send yourself a message, check you land on the thank-you page and check your inbox (look in spam the first time).

Before pushing you can also open contact.html straight from disk or a local server: the form posts the same way, because SilentForms accepts submissions from any origin unless you restrict it.

Using Jekyll#

When GitHub Pages publishes from a branch, it builds the site with Jekyll by default. You can keep the plain HTML above, or move the form into a reusable include with the key in _config.yml. The Jekyll guide shows that setup, and it needs no plugins. If your site is built by another tool through GitHub Actions, follow the guide for that tool instead.

Custom domains and HTTPS#

After you set a custom domain under Settings, Pages, update the redirect URL to the new domain, otherwise visitors are sent to the old github.io address. Turn on Enforce HTTPS on the same page so the form page and the thank-you page are served securely.

Restrict the form to your site#

The access key is visible in your public repository, so anyone could copy the form to their own site. In the dashboard you can add allowed domains to the form, and submissions from other sites are refused with "This form does not accept submissions from this domain." A bare domain covers its subdomains, which has a consequence here:

  • With a custom domain, add example.com.
  • On github.io, add your own host, username.github.io. Never add github.io on its own: that would allow every GitHub Pages site.

This is a deterrent rather than a lock, since scripts can leave out the Origin header. Details in Restrict to your domain.

Gotchas#

  • The form posts to your own site and fails. The action still points at a path on GitHub Pages, which cannot accept POST requests. It must be the SilentForms endpoint.
  • Changes do not show up. Deployments take a minute or two. Check the Actions tab for the latest Pages run.
  • "Access key is required." The hidden field is missing or its name is not accessKey.

For every error message, see Troubleshooting.

Next steps#