---
title: "Add forms to Ghost"
description: "Add custom forms to your Ghost blog. Forminit handles submissions, file uploads, and notifications for you."
url: https://forminit.com/docs/ghost/
---

# Add forms to Ghost

Add onbrand, custom forms to your Ghost blog. Forminit handles submissions, validation, file uploads, and notifications so you don't have to.

---

## Overview

Ghost supports custom HTML through its editor and code injection features. You can add Forminit forms to:

- Individual posts and pages using HTML cards
- Your entire site using Ghost's Code Injection settings
- Custom theme templates

---

## Prerequisites

1. Create a Forminit account at [forminit.com](https://forminit.com)
2. Create a form in your dashboard
3. Set authentication mode to **Public** in Form Settings

> **Caution**
>
> Ghost integrations are client-side only. Never use API keys in Ghost as they would be exposed in your page source.

---

## Adding a Form to a Post or Page

Use Ghost's HTML card to embed a form directly in your content.

### Step 1: Create an HTML Card

1. Open the Ghost editor for your post or page
2. Click the **+** button to add a new card
3. Select **HTML** from the card options

### Step 2: Add the Form HTML

Paste the following code into the HTML card:

```html
<form id="contact-form">
  <div style="margin-bottom: 1rem;">
    <input 
      type="text" 
      name="fi-sender-firstName" 
      placeholder="First name" 
      required 
      style="width: 100%; padding: 0.75rem; border: 1px solid #e5e5e5; border-radius: 4px;"
    />
  </div>
  <div style="margin-bottom: 1rem;">
    <input 
      type="text" 
      name="fi-sender-lastName" 
      placeholder="Last name" 
      required 
      style="width: 100%; padding: 0.75rem; border: 1px solid #e5e5e5; border-radius: 4px;"
    />
  </div>
  <div style="margin-bottom: 1rem;">
    <input 
      type="email" 
      name="fi-sender-email" 
      placeholder="Email" 
      required 
      style="width: 100%; padding: 0.75rem; border: 1px solid #e5e5e5; border-radius: 4px;"
    />
  </div>
  <div style="margin-bottom: 1rem;">
    <textarea 
      name="fi-text-message" 
      placeholder="Message" 
      required 
      rows="5"
      style="width: 100%; padding: 0.75rem; border: 1px solid #e5e5e5; border-radius: 4px; resize: vertical;"
    ></textarea>
  </div>
  
  <p id="form-result" style="margin-bottom: 1rem;"></p>
  
  <button 
    type="submit" 
    style="background: #000; color: #fff; padding: 0.75rem 1.5rem; border: none; border-radius: 4px; cursor: pointer;"
  >
    Send Message
  </button>
</form>

<script src="https://forminit.com/sdk/v1/forminit.js"></script>
<script>
  (function() {
    const forminit = new Forminit();
    const FORM_ID = 'YOUR_FORM_ID'; // ← Replace with your Form ID
    
    const form = document.getElementById('contact-form');
    const resultEl = document.getElementById('form-result');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      const submitBtn = form.querySelector('button[type="submit"]');
      const originalText = submitBtn.textContent;
      submitBtn.textContent = 'Sending...';
      submitBtn.disabled = true;
      
      const formData = new FormData(form);
      const { data, redirectUrl, error } = await forminit.submit(FORM_ID, formData);
      
      if (error) {
        resultEl.textContent = error.message;
        resultEl.style.color = '#dc2626';
        submitBtn.textContent = originalText;
        submitBtn.disabled = false;
        return;
      }
      
      resultEl.textContent = 'Message sent successfully!';
      resultEl.style.color = '#16a34a';
      form.reset();
      submitBtn.textContent = originalText;
      submitBtn.disabled = false;
    });
  })();
</script>
```

### Step 3: Replace Your Form ID

Replace `YOUR_FORM_ID` with your actual Form ID from the Forminit dashboard.

---

## Site-Wide Forms with Code Injection

For forms that appear across your entire site (like newsletter signups in the footer), use Ghost's Code Injection feature.

### Step 1: Open Code Injection Settings

1. Go to your Ghost Admin panel
2. Navigate to **Settings → Code injection**

### Step 2: Add the SDK to Site Footer

In the **Site Footer** section, add:

```html
<script src="https://forminit.com/sdk/v1/forminit.js"></script>
```

### Step 3: Add Forms to Your Theme

Now you can add forms anywhere in your theme templates. The SDK will be available globally.

Example newsletter signup form for your theme:

```html
<form id="newsletter-form">
  <input 
    type="email" 
    name="fi-sender-email" 
    placeholder="Enter your email" 
    required 
  />
  <button type="submit">Subscribe</button>
</form>

<p id="newsletter-result"></p>

<script>
  (function() {
    const forminit = new Forminit();
    const FORM_ID = 'YOUR_FORM_ID';
    
    const form = document.getElementById('newsletter-form');
    const resultEl = document.getElementById('newsletter-result');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      const formData = new FormData(form);
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      if (error) {
        resultEl.textContent = error.message;
        return;
      }
      
      resultEl.textContent = 'Thanks for subscribing!';
      form.reset();
    });
  })();
</script>
```

---

## Form Examples

### Contact Form

```html
<form id="contact-form">
  <input type="text" name="fi-sender-firstName" placeholder="First name" required />
  <input type="text" name="fi-sender-lastName" placeholder="Last name" required />
  <input type="email" name="fi-sender-email" placeholder="Email" required />
  <input type="tel" name="fi-sender-phone" placeholder="Phone (optional)" />
  <textarea name="fi-text-message" placeholder="Your message" required></textarea>
  <button type="submit">Send</button>
</form>

<p id="contact-result"></p>

<script src="https://forminit.com/sdk/v1/forminit.js"></script>
<script>
  (function() {
    const forminit = new Forminit();
    const FORM_ID = 'YOUR_FORM_ID';
    
    const form = document.getElementById('contact-form');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      const formData = new FormData(form);
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      const resultEl = document.getElementById('contact-result');
      
      if (error) {
        resultEl.textContent = error.message;
        return;
      }
      
      resultEl.textContent = 'Message sent successfully!';
      form.reset();
    });
  })();
</script>
```

### Feedback Form with Rating

```html
<form id="feedback-form">
  <input type="text" name="fi-sender-fullName" placeholder="Your name" required />
  <input type="email" name="fi-sender-email" placeholder="Email" required />
  
  <label>How would you rate your experience? (1-5)</label>
  <select name="fi-rating-experience" required>
    <option value="">Select rating</option>
    <option value="5">5 - Excellent</option>
    <option value="4">4 - Good</option>
    <option value="3">3 - Average</option>
    <option value="2">2 - Poor</option>
    <option value="1">1 - Very Poor</option>
  </select>
  
  <textarea name="fi-text-feedback" placeholder="Your feedback" required></textarea>
  <button type="submit">Submit Feedback</button>
</form>

<p id="feedback-result"></p>

<script src="https://forminit.com/sdk/v1/forminit.js"></script>
<script>
  (function() {
    const forminit = new Forminit();
    const FORM_ID = 'YOUR_FORM_ID';
    
    const form = document.getElementById('feedback-form');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      const formData = new FormData(form);
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      const resultEl = document.getElementById('feedback-result');
      
      if (error) {
        resultEl.textContent = error.message;
        return;
      }
      
      resultEl.textContent = 'Thank you for your feedback!';
      form.reset();
    });
  })();
</script>
```

### Guest Post Submission with File Upload

```html
<form id="guest-post-form">
  <input type="text" name="fi-sender-fullName" placeholder="Your name" required />
  <input type="email" name="fi-sender-email" placeholder="Email" required />
  <input type="url" name="fi-url-website" placeholder="Your website (optional)" />
  
  <input type="text" name="fi-text-title" placeholder="Article title" required />
  <textarea name="fi-text-pitch" placeholder="Brief pitch for your article" required></textarea>
  
  <label>Upload your article (PDF, DOC, DOCX)</label>
  <input type="file" name="fi-file-article" accept=".pdf,.doc,.docx" required />
  
  <button type="submit">Submit Guest Post</button>
</form>

<p id="guest-post-result"></p>

<script src="https://forminit.com/sdk/v1/forminit.js"></script>
<script>
  (function() {
    const forminit = new Forminit();
    const FORM_ID = 'YOUR_FORM_ID';
    
    const form = document.getElementById('guest-post-form');
    
    form.addEventListener('submit', async function(event) {
      event.preventDefault();
      
      const submitBtn = form.querySelector('button[type="submit"]');
      submitBtn.textContent = 'Uploading...';
      submitBtn.disabled = true;
      
      const formData = new FormData(form);
      const { data, error } = await forminit.submit(FORM_ID, formData);
      
      const resultEl = document.getElementById('guest-post-result');
      
      if (error) {
        resultEl.textContent = error.message;
        submitBtn.textContent = 'Submit Guest Post';
        submitBtn.disabled = false;
        return;
      }
      
      resultEl.textContent = 'Thank you! We\'ll review your submission and get back to you.';
      form.reset();
      submitBtn.textContent = 'Submit Guest Post';
      submitBtn.disabled = false;
    });
  })();
</script>
```

---

## Available Form Blocks

For complete documentation on all available blocks, field naming conventions, and validation rules, see the [Form Blocks Reference](https://forminit.com/docs/form-blocks/).

---

## Error Handling

Handle common errors appropriately:

```javascript
const { data, error } = await forminit.submit(FORM_ID, formData);

if (error) {
  let message = error.message;
  
  switch (error.error) {
    case 'FI_SCHEMA_FORMAT_EMAIL':
      message = 'Please enter a valid email address.';
      break;
    case 'FI_RULES_PHONE_INVALID':
      message = 'Please enter a valid phone number (e.g., +12025550123).';
      break;
    case 'FI_SCHEMA_RANGE_RATING':
      message = 'Rating must be between 1 and 5.';
      break;
    case 'TOO_MANY_REQUESTS':
      message = 'Please wait a moment before submitting again.';
      break;
  }
  
  resultEl.textContent = message;
  return;
}
```

### Common Error Codes

| Error Code | Description |
|------------|-------------|
| `FORM_NOT_FOUND` | Form ID doesn't exist or was deleted |
| `FORM_DISABLED` | Form is disabled by owner |
| `EMPTY_SUBMISSION` | No fields with values submitted |
| `FI_SCHEMA_FORMAT_EMAIL` | Invalid email format |
| `FI_RULES_PHONE_INVALID` | Invalid phone number format |
| `FI_SCHEMA_RANGE_RATING` | Rating not between 1-5 |
| `FI_DATA_COUNTRY_INVALID` | Invalid country code |
| `TOO_MANY_REQUESTS` | Rate limit exceeded |

---

## Related Documentation

- [Form Blocks Reference](https://forminit.com/docs/form-blocks/): Complete reference for all block types
- [File Uploads](https://forminit.com/docs/file-upload/): Detailed file upload guide
- [API Reference](https://forminit.com/docs/submit-form-api/): Full REST API documentation
- [HTML Integration](https://forminit.com/docs/html/): General HTML/static site setup
- [Cloudflare Turnstile Integration](https://forminit.com/docs/cloudflare-turnstile/): Add Turnstile protection
- [reCAPTCHA Integration](https://forminit.com/docs/recaptcha/): Add reCAPTCHA protection
- [hCaptcha Integration](https://forminit.com/docs/hcaptcha/): Add hCaptcha protection
- [Honeypot](https://forminit.com/docs/honeypot/): Add honeypot spam protection
