Getting Started

FramerSend lets you connect Framer forms to any CRM, email tool, or database — without exposing API keys in your client code. Here's how it works in 3 steps:

1

Purchase a connector

Browse our connectors catalog and buy the one you need ($19 one-time). You'll receive instant access after payment.

2

Set up in the dashboard

Sign in to your FramerSend dashboard. Add a Connection (paste your CRM credentials), then create a Form and map your fields.

3

Install the Framer override

Copy the generated Form ID and paste it into the FramerSend code override in your Framer project. That's it — submissions will flow to your CRM automatically.

Connect to Framer

FramerSend offers two ways to connect your forms. We highly recommend Method 1 for a completely No-Code experience.

Method 1: Native Webhook URL (Quick Setup)

1

Get your Webhook URL

In your FramerSend Dashboard, copy the Webhook URL generated for your form (e.g., https://framersend.com/api/submit/fs_...).

2

Paste into Framer

Select your native Framer Form on the canvas. In the right property panel, set the Action to URL and paste your Webhook URL into the Submit URL field. Publish and you're done!

Method 2: Custom Component (Pro Features)

Use this method if you want advanced features like Anti-Spam (IP Rate Limiting) and beautiful UI Error notifications.

1

Create a Code Component

In your Framer project, open the Assets panel (left sidebar). Click the + icon next to "Code" and select "New component".

2

Paste the Code

Name it FramerSendWrapper, replace all default code with the following, then save:

typescript
import * as React from "react"
import { addPropertyControls, ControlType, RenderTarget } from "framer"
import { useFramerSend } from "https://framersend.vercel.app/sdk.js"

export default function FramerSendWrapper(props) {
    const { formId, scrollId, previewMode, modalBgColor, textColor, buttonColor } = props
    const isCanvas = RenderTarget.current() === RenderTarget.canvas
    
    // Core logic is handled by the CDN SDK
    const { modalConfig, markerRef, setModalConfig } = useFramerSend({ formId, scrollId, isCanvas, React })

    // On Canvas: show a small visual indicator
    if (isCanvas && !previewMode) {
        return (
            <div
                ref={markerRef}
                style={{
                    width: 150, height: 36, background: formId ? "#6d28d9" : "#d97706",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    borderRadius: 20, color: "#fff", fontSize: 11, fontWeight: 700,
                }}
            >
                <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{marginRight: 6}}><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z" /></svg>
                {formId ? "FramerSend" : "Set Form ID"}
            </div>
        )
    }

    // Modal UI (Fully Customizable)
    const activeModal = isCanvas && previewMode 
        ? { type: 'error', title: "Preview Error", message: "This is how your error will look to users. You can customize the colors in the right panel.", actionLabel: "Dismiss" }
        : modalConfig

    if (!activeModal) return <div ref={markerRef} style={{ position: "absolute", width:0, height:0, opacity:0, pointerEvents:"none" }} />

    return (
        <div ref={markerRef} style={isCanvas ? { width: "100%", height: "100%", position: "absolute", top:0, left:0, zIndex: 999999 } : { position: "absolute", width:0, height:0 }}>
            <div style={{ position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0,0,0,0.5)", backdropFilter: "blur(4px)", WebkitBackdropFilter: "blur(4px)", zIndex: 2147483647, display: "flex", alignItems: "center", justifyContent: "center", padding: 20, fontFamily: "Inter, sans-serif" }} onClick={() => setModalConfig && setModalConfig(null)}>
                <div style={{ background: modalBgColor, borderRadius: 16, padding: "32px 24px", width: "100%", maxWidth: 400, boxShadow: "0 20px 40px rgba(0,0,0,0.2)", textAlign: "center" }} onClick={e => e.stopPropagation()}>
                    <div style={{ width: 64, height: 64, borderRadius: "50%", background: activeModal.type === 'success' ? '#ecfdf5' : '#fef2f2', color: activeModal.type === 'success' ? '#10b981' : '#ef4444', display: 'flex', alignItems: 'center', justifyContent: 'center', margin: '0 auto 20px' }}>
                        {activeModal.type === 'success' ? (
                            <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
                        ) : (
                            <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="15" y1="9" x2="9" y2="15"></line><line x1="9" y1="9" x2="15" y2="15"></line></svg>
                        )}
                    </div>
                    <h3 style={{ margin: "0 0 12px", fontSize: 20, fontWeight: 700, color: textColor }}>{activeModal.title}</h3>
                    <p style={{ margin: "0 0 24px", fontSize: 15, color: textColor, opacity: 0.8, lineHeight: 1.5 }}>{activeModal.message}</p>
                    <button onClick={() => setModalConfig && setModalConfig(null)} style={{ width: "100%", padding: "12px 0", background: buttonColor, color: "#fff", border: "none", borderRadius: 8, fontSize: 15, fontWeight: 600, cursor: "pointer" }}>
                        {activeModal.actionLabel || "Got it"}
                    </button>
                </div>
            </div>
        </div>
    )
}

addPropertyControls(FramerSendWrapper, {
    formId: { type: ControlType.String, title: "Form ID", placeholder: "Paste your Form ID" },
    scrollId: { type: ControlType.String, title: "Scroll ID", placeholder: "Optional: e.g. my-form" },
    previewMode: { type: ControlType.Boolean, title: "Preview UI", defaultValue: false },
    modalBgColor: { type: ControlType.Color, title: "Modal BG", defaultValue: "#ffffff" },
    textColor: { type: ControlType.Color, title: "Text Color", defaultValue: "#111827" },
    buttonColor: { type: ControlType.Color, title: "Button", defaultValue: "#6d28d9" },
})
3

Place it on your page

Drag the FramerSendWrapper from Assets onto your page — place it anywhere near your form (above, below, or beside). It auto-detects the form on your page.

4

Paste your Form ID

Click the FramerSendWrapper pill on the canvas. In the right panel, paste your Form ID from the FramerSend dashboard. The pill turns purple to confirm.

5

Customize UI (Optional)

In the Framer properties panel (right side), toggle Preview UI to see the Error Modal directly on your canvas. From there, you can fully customize the Modal BG, Text Color, and Button Color to match your brand perfectly.

That's it! The component is invisible on your live site. It automatically captures form submissions and sends data to FramerSend. Publish your site and test!

Connect a CRM

After purchasing a connector, head to your dashboard to set up the connection. Each CRM requires different credentials — here's a guide for the most popular ones.

Klaviyo

Required: Private API Key + List ID

Where to find: Settings → API Keys → Create Private Key

Mailchimp

Required: API Key + Server Prefix + Audience ID

Where to find: Account → Extras → API Keys

HubSpot

Required: Private App Access Token

Where to find: Settings → Integrations → Private Apps → Create

Google Sheets

Required: Refresh Token + Spreadsheet ID

Where to find: OAuth2 flow — contact support for help

Slack

Required: Incoming Webhook URL

Where to find: Slack Apps → Incoming Webhooks → Add

Zapier

Required: Webhook URL

Where to find: Create Zap → Webhooks by Zapier → Catch Hook

💡 Tip: For all other connectors, the credential fields are labeled with exact instructions on where to find each value in your CRM settings.

File Uploads & Cloud Storage

FramerSend supports native file uploads. When visitors submit files through your form, FramerSend uploads them directly to your preferred cloud storage provider (Google Drive, AWS S3, or Supabase Storage) and routes the secure file URLs directly to your CRM properties.

1

Set up a Storage Connection

In your Dashboard, navigate to Connections, click **Add Connection**, and select Google Drive, AWS S3, or Supabase Storage. Enter your credentials to link the account securely.

2

Link Storage to your Form

Go to the Forms tab, click **Edit** on your form, select your storage connector from the **File Storage Connection** dropdown, and configure upload limitations (e.g. maximum file size).

3

Integrate the Custom React Component

Under your form's dashboard settings, click **Copy File Upload Integration Code**. In your Framer canvas, create a new Code Component named `FramerFileUpload`, paste this code, and place the component inside your native form container.

4

Map to your CRM

Under **Field Mapping**, link your form's file upload field name to your target CRM contact or lead property. Submissions to your CRM will now contain the secure, public link to the uploaded file.

🔒 Security: All file uploads are streamed directly to your bucket through the server side, keeping your cloud keys completely hidden from client-side inspectors.

Field Mapping

Field mapping tells FramerSend how to translate your Framer form field names into CRM property names. For example:

Framer Form FieldKlaviyo Property
email$email
name$first_name
phone$phone_number
company$organization

In the dashboard, each form has a Field Mapping section with dropdown menus pre-populated with the CRM's accepted properties. Simply select the matching CRM field for each Framer form field.

API Reference

If you want to integrate FramerSend manually (without the Framer override), you can call our API directly.

POST/api/submit/{formId}

Submit form data to be routed to the connected CRM.

Headers

headers
Content-Type: application/json
Origin: https://your-framer-site.com

Request Body

json
{
  "email": "user@example.com",
  "name": "Jane Doe",
  "phone": "+1234567890",
  "message": "I'd like to learn more"
}

Response (200 OK)

json
{
  "success": true,
  "id": "sub_abc123"
}

Error Response (429)

json
{
  "error": "Rate limit exceeded",
  "retryAfter": 60
}

Rate Limits: 10 requests per minute per IP. The X-RateLimit-Remaining header shows remaining requests.

FAQ & Troubleshooting

My form submissions aren't showing up in my CRM

Check the following: (1) Your Form ID is correct in the override code, (2) Your CRM credentials are valid in the dashboard, (3) Your field mapping includes at least the email field. Check the Submissions tab in your dashboard for error logs.

Can I use FramerSend with a custom domain?

Yes! FramerSend works with any domain. Just make sure your Framer site's domain is set as the allowed origin in your form settings.

What happens if a submission fails?

Failed submissions are logged in your dashboard with the error message. You can retry them manually or fix the issue and resubmit.

Is there a submission limit?

Each connector includes 500 submissions per month. The All-in-One Bundle includes unlimited submissions.

Can I connect multiple CRMs to one form?

Currently each form connects to one CRM. To send to multiple CRMs, create separate forms with different Form IDs.

How do I update my CRM credentials?

Go to Dashboard → Connections → click your connection → Update Credentials. Your existing forms will automatically use the new credentials.

Do you support Framer's native form element?

Yes! The code override works with Framer's built-in form component. Apply the withFramerSend override to your form element.

Is my data secure?

Absolutely. All credentials are encrypted at rest. Your API keys never appear in client-side code — only a public Form ID is exposed. We use HTTPS for all data transmission.

Still need help?

Reach out and we'll get back to you within 24 hours.

Contact Support →