# Modifee > Modifee lets agencies and freelance developers give their clients an AI chat inside the apps they deliver; the client asks for changes in plain language, an AI agent edits the code, opens a PR on GitHub and deploys a preview. Small changes can auto-merge; the agency keeps control of the rest. ## Product Modifee lets agencies and freelance developers give their clients an AI chat inside the apps they deliver; the client asks for changes in plain language, an AI agent edits the code, opens a PR on GitHub and deploys a preview. Small changes can auto-merge; the agency keeps control of the rest. For agencies, freelancers, and dev studios that ship client-specific projects with GitHub and Vercel. ### How it works The client asks in the widget, an agent edits the code and opens a pull request on GitHub, and a preview is deployed. Small changes can auto-merge; the agency keeps control of the rest. 1. The client asks for the change in plain language, in the chat on their site. 2. An AI agent edits the repository, opens a pull request on GitHub, and a preview is deployed. 3. A small change can auto-merge after the client approves. Larger changes wait for the agency. ### Integrations Works with GitHub, Vercel, Heroku Review Apps, and Shopify themes, plus any host that posts previews to GitHub. ## Pricing Plans are monthly, in USD, plus applicable taxes. Small edits use 1 credit, bigger changes like new pages use more. Paid plans bill $0.60 per extra credit. - Free: $0 USD/month. 15 credits / month. no overage. no credit rollover. - Starter: $39 USD/month. 150 credits / month. $0.60 per extra credit. unused credits roll over 1 month. - Studio: $129 USD/month. 600 credits / month. $0.60 per extra credit. unused credits roll over 1 month. - Agency: $349 USD/month. 2000 credits / month. $0.60 per extra credit. unused credits roll over 1 month. Included in every plan: - Unlimited projects - White-label widget - Previews without a host account - Works with any host - Built-in quotes - Auto-merge is optional. Autopilot Off means every change waits for the agency. Full pricing page: https://www.modifee.com/pricing ## Comparisons / FAQ ### What is Modifee? Modifee lets agencies and freelance developers give their clients an AI chat inside the apps they deliver; the client asks for changes in plain language, an AI agent edits the code, opens a PR on GitHub and deploys a preview. Small changes can auto-merge; the agency keeps control of the rest. ### How does Modifee work with GitHub and Vercel? Each project is one GitHub repository. Modifee opens a pull request, and Vercel builds a preview from that pull request. The client reviews the preview. The pull request is squash-merged into the default branch, and the site's existing production deploy ships it. ### Does it work with Heroku? Yes. Preview detection works with Heroku Review Apps and with any host that posts deployment status to GitHub. The widget can be installed on HTML, Next.js, WordPress, Webflow, and Shopify themes (theme.liquid). ### Can my client break production? The chat does not commit to the default branch. The change stays on a pull request until it is merged. Auto-merge runs only after the client approves a change the project's Autopilot mode allows. Protected paths, deleted files, and diffs over the file and line caps always wait for the agency. Autopilot can be set to Off so every merge waits for you. ### What changes can auto-merge? Off: Every change waits for you. Safe: Text, styles, and links. Standard: Also new pages, long copy, and small UI additions. Aggressive: Same scope as Standard, with a higher file and line cap. New projects start on Aggressive. Auto-merge runs only after the client approves, and only when a preview is ready on the pull request. Protected paths, deleted files, and diffs over that mode's file and line caps always wait for the agency. ### Do I need my own Anthropic or OpenAI key? No. You do not need your own Anthropic or OpenAI key. AI usage is included in the plan and metered in credits. ### How is it priced? Monthly plans in USD, plus applicable taxes. Free is $0 USD/month (15 credits / month, no overage, no credit rollover). Starter is $39 USD/month (150 credits / month, $0.60 per extra credit, unused credits roll over 1 month). Studio is $129 USD/month (600 credits / month, $0.60 per extra credit, unused credits roll over 1 month). Agency is $349 USD/month (2000 credits / month, $0.60 per extra credit, unused credits roll over 1 month). Small edits use 1 credit, bigger changes like new pages use more. Details are on https://www.modifee.com/pricing. ### Is it for multi-tenant SaaS? No. Modifee is built for client-specific projects. One project is one GitHub repository for one client site. It is not a shared multi-tenant application used by many customers of the same product. ### What do you store from my code? We don't keep copies of your repository. Code is only read inside a temporary sandbox during a request. ### What if the change is too big? Large requests are held for a quote instead of being attempted. The agency sends the quote, and the coding agent starts after the client accepts. Backend, auth, payments, personal data, and protected paths are held that way. ## Docs # Docs Guides for installing Modifee, giving clients access, and fixing common problems. ## Getting started - [What is Modifee](https://www.modifee.com/docs/getting-started/what-is-modifee.md): A client describes a site change in the widget, and Modifee opens a pull request you can preview and merge. - [Quickstart](https://www.modifee.com/docs/getting-started/quickstart.md): Go from a new account to a merged test change on a connected GitHub repository. ## Install - [Next.js App Router](https://www.modifee.com/docs/install/nextjs-app-router.md): Add the widget script to the Next.js root layout, then confirm Widget install is complete. - [Next.js Pages Router](https://www.modifee.com/docs/install/nextjs-pages-router.md): Add the widget script to pages/_document, then confirm Widget install is complete. - [HTML and static sites](https://www.modifee.com/docs/install/html.md): Paste the widget script before the closing body tag on an HTML or static site, then confirm Widget install is complete. - [Other frameworks](https://www.modifee.com/docs/install/other-frameworks.md): Add the widget script on Vite, Astro, Flask, Django, Laravel, or Rails, then confirm Widget install is complete. ## Client access - [Auth methods](https://www.modifee.com/docs/client-access/auth-methods.md): Choose Site without login or App with login, and see what the client does before a request is accepted. - [Access marker](https://www.modifee.com/docs/client-access/access-marker.md): Choose the URL marker that shows the widget on a site without login, and replace the link when it changes. - [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails.md): Add or remove the people who can request changes, and send a test request from the agency. ## Vercel & previews - [Vercel integration](https://www.modifee.com/docs/vercel/integration.md): Install the Vercel integration, choose the project, and grant access when that project is missing from the list. - [Signing secret](https://www.modifee.com/docs/vercel/signing-secret.md): Store MODIFEE_SECRET, push it to Vercel Production and Preview, and regenerate it when the value must change. - [Redeploy](https://www.modifee.com/docs/vercel/redeploy.md): Redeploy production after MODIFEE_SECRET is pushed so the running site picks up the new value. - [Protected previews](https://www.modifee.com/docs/vercel/protected-previews.md): Open Vercel-protected preview deployments for clients, and leave other hosts on GitHub detection. ## Using the widget - [For clients](https://www.modifee.com/docs/widget/for-clients.md): How to ask for a site change in the widget, review the preview, and read the messages you may see. - [Voice dictation](https://www.modifee.com/docs/widget/voice-dictation.md): Dictate a widget request into the text box, and how that recording is billed. ## Agency workflow - [Inbox](https://www.modifee.com/docs/agency/inbox.md): What each request status asks you to do, and what the Test badge means. - [Quotes and merges](https://www.modifee.com/docs/agency/quotes-and-merges.md): Send a quote, see what the client gets, then merge, retry, or reject. - [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits.md): The Autopilot and limits settings, their defaults, and the plan's credits. - [Guardrails](https://www.modifee.com/docs/agency/guardrails.md): Paths the coding agent must not change, the defaults, and how to edit the list. - [Health indicators](https://www.modifee.com/docs/agency/health-indicators.md): The Home light, and the green or yellow mark on each project Settings section. ## Troubleshooting - [Symptom index](https://www.modifee.com/docs/troubleshooting/index.md): Match a symptom to a troubleshooting page, and the error codes that show up most often. - [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing.md): The change button never appears on the client site. - [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed.md): The widget refuses the client's email. - [Token errors](https://www.modifee.com/docs/troubleshooting/token-errors.md): App with login: the widget cannot verify the signed client token. - [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy.md): MODIFEE_SECRET is missing on Vercel, or a redeploy did not pick it up. - [Previews](https://www.modifee.com/docs/troubleshooting/previews.md): No preview was detected, the preview is protected, or the last check failed. - [Agent and pull request](https://www.modifee.com/docs/troubleshooting/agent-and-pr.md): The agent failed, no pull request was opened, or a monthly limit stopped the request. - [Billing and plan](https://www.modifee.com/docs/troubleshooting/billing-and-plan.md): A plan limit, a missing billing account, a checkout that did not open, or the project's monthly request cap. ## Errors - [Error catalog](https://www.modifee.com/docs/errors.md): Every Modifee error code, with what caused it and how to fix it. - [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001.md): You need to sign in. - [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002.md): This email isn't allowed to request changes on this site. - [MDF-AUTH-003](https://www.modifee.com/docs/errors/MDF-AUTH-003.md): You don't have access to this. - [MDF-AUTH-004](https://www.modifee.com/docs/errors/MDF-AUTH-004.md): That code is incorrect or has expired. - [MDF-AUTH-005](https://www.modifee.com/docs/errors/MDF-AUTH-005.md): Too many attempts. Request a new code. - [MDF-REQ-001](https://www.modifee.com/docs/errors/MDF-REQ-001.md): Something was off with that request. - [MDF-REQ-002](https://www.modifee.com/docs/errors/MDF-REQ-002.md): We couldn't find that. - [MDF-REQ-003](https://www.modifee.com/docs/errors/MDF-REQ-003.md): That conflicted with the current state. - [MDF-REQ-004](https://www.modifee.com/docs/errors/MDF-REQ-004.md): You've used the adjustments included with this change. - [MDF-QUOTA-001](https://www.modifee.com/docs/errors/MDF-QUOTA-001.md): Request received — your team has been notified and will process it shortly. - [MDF-QUOTA-002](https://www.modifee.com/docs/errors/MDF-QUOTA-002.md): Too many requests. Try again in a moment. - [MDF-QUOTA-003](https://www.modifee.com/docs/errors/MDF-QUOTA-003.md): Too many codes requested. Try again in a few minutes. - [MDF-PLAN-001](https://www.modifee.com/docs/errors/MDF-PLAN-001.md): This workspace is over its plan limit. - [MDF-PLAN-002](https://www.modifee.com/docs/errors/MDF-PLAN-002.md): This workspace has no billing account yet. - [MDF-PLAN-003](https://www.modifee.com/docs/errors/MDF-PLAN-003.md): Billing could not be opened. - [MDF-PLAN-004](https://www.modifee.com/docs/errors/MDF-PLAN-004.md): You've reached this month's request limit. Your team can raise it. - [MDF-WIDGET-001](https://www.modifee.com/docs/errors/MDF-WIDGET-001.md): That file could not be attached. - [MDF-WIDGET-002](https://www.modifee.com/docs/errors/MDF-WIDGET-002.md): Transcription failed. - [MDF-WIDGET-003](https://www.modifee.com/docs/errors/MDF-WIDGET-003.md): The sign-in email could not be sent. - [MDF-WIDGET-004](https://www.modifee.com/docs/errors/MDF-WIDGET-004.md): Allow the microphone in your browser to dictate. - [MDF-WIDGET-005](https://www.modifee.com/docs/errors/MDF-WIDGET-005.md): The connection was lost. - [MDF-VERCEL-001](https://www.modifee.com/docs/errors/MDF-VERCEL-001.md): Vercel could not complete that request. - [MDF-VERCEL-002](https://www.modifee.com/docs/errors/MDF-VERCEL-002.md): The preview signing secret is missing or was not saved. - [MDF-VERCEL-003](https://www.modifee.com/docs/errors/MDF-VERCEL-003.md): The preview could not be opened. - [MDF-INTERNAL-001](https://www.modifee.com/docs/errors/MDF-INTERNAL-001.md): Something broke on our end. We've been notified. - [MDF-INTERNAL-002](https://www.modifee.com/docs/errors/MDF-INTERNAL-002.md): Modifee is briefly unavailable. # What is Modifee A client describes a site change in the widget, and Modifee opens a pull request you can preview and merge. Modifee is a workspace in the dashboard. You connect a GitHub repository for a client site, add a chat widget to that site, and the client asks for a change in plain language. A coding agent opens a pull request. The client reviews a preview. The change is squash-merged into the default branch. The English widget button is **Request a change**. The same strings exist in French and Spanish. Dashboard labels stay in English. ## Who it's for Agencies and freelance developers who ship client sites from GitHub. One workspace holds the projects. Each project is one repository. Clients never see the **Project name**. ## How a change moves 1. The client opens **Request a change** and describes the edit. The empty state says "A change to make on your site?" and "Describe it in a few words. You'll get a preview to approve before it goes live." 2. Modifee classifies the request. A small change is queued for the coding agent. A large one is held: backend, auth, payments, personal data, a third-party service, a form that saves or sends data, a whole-site redesign, an ambiguous scope, a protected path, or a change that is too large. The dashboard status is **Needs a quote**. Open the request from the **Inbox** and press **Send quote to client**. The client presses **Accept** or **Decline**. **Accept** queues the agent. Until then the widget says `In review by` and the team name. 3. The agent edits the repository and opens a pull request. The dashboard shows **Agent running**, then **Building preview**. 4. The client reviews the preview and presses **Looks good**. The widget status is "Preview ready — please review". If no preview is available, the dashboard shows **No preview** and the widget says `Ready for` the team name `to review`. 5. The pull request is squash-merged into the default branch. You press **Approve & merge**, or [Autopilot](https://www.modifee.com/docs/agency/autopilot-and-limits) merges an eligible change after **Looks good**. The widget then says **Live**. The dashboard status is **Merged**. New projects store Autopilot as **Aggressive**. That mode can merge trivial and standard changes after the client approves. **Off** waits for **Approve & merge** on every change. Protected files always wait for you. ## What Modifee does not do - It does not commit the change straight to the default branch. The work is a pull request until it is merged. - It does not start the coding agent on a **Needs a quote** request until the client presses **Accept**. - It does not let the agent edit a protected path. Those requests are held for a quote, and the agent blocks writes to those files. See [Guardrails](https://www.modifee.com/docs/agency/guardrails). - It does not show the widget to every visitor when **Authentication** is **Site without login**. The button stays hidden until the client opens the access-marker link. Only addresses under **Who can request changes?** can send a request. Anyone else sees "This email isn't allowed to request changes on this site." - It does not show the widget to guests when **Authentication** is **App with login**. The page must pass a signed `data-token`. Without it, the browser console says "Modifee: data-project and data-token are required". - It does not host the client site. You keep deploying the site. Modifee reads the repository you connect and opens pull requests on it. Next: [Quickstart](https://www.modifee.com/docs/getting-started/quickstart). # Quickstart Go from a new account to a merged test change on a connected GitHub repository. ## Prerequisites - A GitHub account that can install a GitHub App on the client repository. - The repository's default branch. The new-project screen labels it **Watching branch**. - The public URL of the deployed site. Local addresses are rejected. ## Steps 1. Open the sign-in page. The heading is **Sign in to Modifee**. Press **Continue with GitHub**. The page says: "Use your GitHub account. We'll ask you to install the Modifee GitHub App on the repos you choose." 2. Open **Projects**. If no GitHub App is installed, the empty state is **Connect GitHub**, with the text "Install the GitHub App before creating a project." Press **Install GitHub App** and grant the repositories you want. 3. Press **New project**. If the list is empty, the empty state is **Connect your first repo** and the button is **Connect a repo**. Choose **Repository** and **Project name**, then press **Create project**. The form states "Approved changes open a pull request on this repo." 4. The project opens on the setup wizard, step **Connect**. Enter **Site URL** (placeholder `https://example.com`) and press **Continue**. You can change it later under **Settings → Connection → Site URL**. 5. On **Client access**, pick how the client opens the widget. **Public site, no login** asks for an email code. **Site with login** uses a server token. Add at least one address under **Who can request changes?** Press **Continue**. Details: [Auth methods](https://www.modifee.com/docs/client-access/auth-methods), [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails), [Access marker](https://www.modifee.com/docs/client-access/access-marker). 6. On **Install the widget**, press **Install automatically** or open **Install manually** and paste the snippet. Install guides: [Next.js App Router](https://www.modifee.com/docs/install/nextjs-app-router), [Next.js Pages Router](https://www.modifee.com/docs/install/nextjs-pages-router), [HTML and static sites](https://www.modifee.com/docs/install/html), [Other frameworks](https://www.modifee.com/docs/install/other-frameworks). 7. Save **Site URL** if you skipped it, deploy the site, then press **Check installation** under **Settings → Widget install**. Continue when the mark beside **Widget install** is green. See the install page for your stack. 8. On the project header, press **Send a test request**. When the site URL is saved and the last check is not unreachable, this opens the live site with the access marker, test mode, and the draft "Change the homepage heading to Welcome". Press **Send** in the widget. The banner says "Test mode — agency". 9. Watch the request in **Inbox** or the project's **Requests** tab. After a preview, press **Looks good** in the widget. Then either Autopilot merges it, or the status is **Needs your merge** and you press **Approve & merge**. The dialog says "Squash-merge this pull request into the default branch." See [Quotes and merges](https://www.modifee.com/docs/agency/quotes-and-merges) and [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits). Previews are a separate wizard step, **Previews**. If the client cannot open the preview, see [Previews](https://www.modifee.com/docs/vercel/protected-previews) and [Preview problems](https://www.modifee.com/docs/troubleshooting/previews). ## Verify The request status in the dashboard is **Merged**. The widget status is **Live**. ## Troubleshooting - Sign-in: "This email is already linked to another sign-in method. Use the original method, or a different GitHub account." "Access was denied. Try again with the GitHub account you use for work." "Sign-in is temporarily unavailable. Try again in a moment." "Something went wrong while signing in. Try again." - Repositories: `Could not load repositories for` and the GitHub account login. Press **Try again**. **No repositories available** links to **Configure GitHub App access**. **Don't see your repository?** opens the GitHub App settings. `Every repository from` the account login `is already connected to a project.` `This repository is already connected to a project.` - Plan cap: "The Free plan includes 1 project." Other plans use the same sentence with their name and limit. The link beside it is **Upgrade to add another.** - Site URL: "Enter a public http(s) URL." "Enter a public site URL. Local addresses can't be used here." - Widget missing: [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing). - "This email isn't allowed to request changes on this site." is [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002). See [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed). - "You've reached this month's request limit." is [MDF-QUOTA-001](https://www.modifee.com/docs/errors/MDF-QUOTA-001). - "This workspace is over its plan limit." is [MDF-PLAN-001](https://www.modifee.com/docs/errors/MDF-PLAN-001). - Preview will not open: [MDF-VERCEL-003](https://www.modifee.com/docs/errors/MDF-VERCEL-003) and [Preview problems](https://www.modifee.com/docs/troubleshooting/previews). # Next.js App Router Add the widget script to the Next.js root layout, then confirm Widget install is complete. ## Prerequisites - A Modifee project whose repository has `next.config.js`, `next.config.mjs`, `next.config.cjs`, or `next.config.ts`. - One root layout: `app/layout.tsx`, `app/layout.jsx`, `src/app/layout.tsx`, or `src/app/layout.jsx`. - **Site URL** saved under **Settings → Connection**. - **Authentication** chosen under **Settings → Client access**. The wizard step **Client access** uses **Public site, no login** and **Site with login** for the same two modes. Settings calls them **Site without login** and **App with login**. The default is **Site without login**. ## Steps Do this from the wizard step **Install the widget**, or from **Settings → Widget install**. ### Site without login 1. Open **Install manually** and select the tab **Next.js (App Router)**. The instruction is "Add this once to the root app/layout.tsx, inside ``." 2. Put this in the root layout. If the layout already exists, add the `Script` import and the `Script` tag. Do not replace the rest of the file. **Install automatically** does the same edit: it inserts `import Script from "next/script"` and places the tag just before ``. ``` import Script from "next/script"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` `YOUR_PROJECT_KEY` is the same key as in step 1. 3. Or press **Install automatically**. The pull request is titled "Install Modifee widget" on branch `modifee/install-widget`. Merge it and wait for the deploy. The screen says "Merged — waiting for deploy" until the check succeeds. **Site without login** does not use `MODIFEE_SECRET`. **App with login** is supported as a manual snippet. **Install automatically** still refuses, with "Pages Router has no server layout we can attach a signed token to without guessing how users log in. Paste the snippet above. No pull request was opened." Open **Install manually** and select **Next.js (Pages Router)**. The widget reads `data-token` on the script tag. It does not call an API for the token. Sign in `getServerSideProps` on each page that should show the widget. `pages/_app.tsx` only receives the token through `pageProps`. Do not import the signing file from `_app`. Do not put the secret in a `NEXT_PUBLIC_` variable. `getSessionUser` is not a Modifee function. Replace it with the call that reads the signed-in user from the request. Store the secret as `MODIFEE_SECRET`. See [Signing secret](https://www.modifee.com/docs/vercel/signing-secret). ``` // server-only — never import this file from client code import crypto from "crypto"; export function modifeeToken(email, name) { const payload = Buffer.from( JSON.stringify({ email, name, exp: Math.floor(Date.now() / 1000) + 86400, }), ).toString("base64url"); const sig = crypto .createHmac("sha256", process.env.MODIFEE_SECRET) .update(payload) .digest("base64url"); return `${payload}.${sig}`; } // pages/index.tsx — add this to each page that should show the widget. Keep the page component. export async function getServerSideProps({ req }) { const { modifeeToken } = await import("@/lib/modifee"); const user = await getSessionUser(req); return { props: { modifeeToken: user?.email ? modifeeToken(user.email, user.name) : null, }, }; } // pages/_app.tsx — do not import the signing file here import Script from "next/script"; export default function App({ Component, pageProps }) { return ( <> {pageProps.modifeeToken ? ( ``` `YOUR_PROJECT_KEY` is the `data-project` value already filled in on the **HTML** tab. The same value is shown under **Settings → Danger zone**. Copy `src` from the tab if it is not `https://www.modifee.com/widget.js`. 2. **Install automatically** writes that tag into the first file it finds among `index.html`, `public/index.html`, and `src/index.html`. It can also target a shared template: `templates/base.html`, `templates/layout.html`, `templates/base.html.jinja`, `app/templates/base.html`, `templates/application.html.erb`, `app/views/layouts/application.html.erb`, `resources/views/layouts/app.blade.php`, or `resources/views/app.blade.php`. Server frameworks are covered in [Other frameworks](https://www.modifee.com/docs/install/other-frameworks). 3. The same tag is on three more tabs: - **WordPress**: "Add this once in the theme footer, or with a plugin that injects a footer script, just before ``." - **Webflow**: "Add this once in **Project settings → Custom code → Footer**, then publish." - **Shopify**: "Add this once in **Online Store → Themes → Edit code → theme.liquid**, just before ``, then save." 4. Or press **Install automatically**. The pull request is titled "Install Modifee widget" on branch `modifee/install-widget`. Merge it, then wait until the screen no longer says "Merged — waiting for deploy". **Site without login** does not use `MODIFEE_SECRET`. **App with login** on a static HTML file stops automatic install: "This site has no server file where a token can be signed. Switch to Site without login to install with one line, or paste the signed-token snippet on your server. No pull request was opened." If you paste that snippet on a server, the response that includes `data-token` must be rendered for each request and must not be cached. A cached page can send one user's token to someone else. See [Other frameworks](https://www.modifee.com/docs/install/other-frameworks). **Install manually** includes an **iOS tip (optional)**: "Add viewport-fit=cover to your viewport meta tag so the button clears the iPhone home bar." ## Verify 1. Publish the page that contains the script. 2. Open **Settings → Widget install**. 3. Press **Check installation**. 4. The text is "Found on the site." and "Widget found on the site." The mark beside **Widget install** turns green. The check reads the HTML Modifee fetches. The script tag must be in that HTML, with this project's `data-project`. A green mark also sticks when the widget has loaded and the stored check did not fail. The yellow tooltip is "Widget not found on the site". ## Troubleshooting - "Add a site URL before checking." - `We couldn't find the widget on` the saved site URL. `Paste the snippet just before and check again.` - `The widget on this page belongs to another project.` - `We couldn't reach` the saved site URL. `Connection failed. The widget will be marked installed as soon as it loads on the site.` The same sentence uses `Timed out` or `HTTP` plus the status code when that is what the check reports. - `This page is rendered in the browser, so the widget script is not in the HTML we fetched from` the saved site URL. `Open the site after you paste the snippet. We'll mark this done as soon as the widget loads.` - "This repo doesn't match a place we can edit safely: Next.js App Router, Next.js Pages Router, Vite + React, Astro, or a root index.html. Paste the snippet above. No pull request was opened." - "The repository tree is too large to choose a file safely. Paste the snippet above. No pull request was opened." - The file path, then `has no tag to attach the widget to. Paste the snippet above. No pull request was opened.` - "This site has no server file where a token can be signed. Switch to Site without login to install with one line, or paste the signed-token snippet on your server. No pull request was opened." - "Missing GitHub permissions. Re-authorize the GitHub App with contents:write and pull_requests:write." - "This repository is archived. No pull request was opened." - "Could not open the pull request." - "This project has no API key yet." - Browser console: "Modifee: data-project is required". "Modifee: missing script element". - The button stays hidden until the client opens the access-marker URL. See [Access marker](https://www.modifee.com/docs/client-access/access-marker) and [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing). - "This email isn't allowed to request changes on this site." is [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002). See [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed). # Other frameworks Add the widget script on Vite, Astro, Flask, Django, Laravel, or Rails, then confirm Widget install is complete. ## Prerequisites - A Modifee project linked to the repository. - **Site URL** saved under **Settings → Connection**. - **Authentication** under **Settings → Client access**. **Site without login** is the default (wizard: **Public site, no login**). **App with login** (wizard: **Site with login**) needs a server that can sign a token. HTML, WordPress, Webflow, and Shopify use the one-line script in [HTML and static sites](https://www.modifee.com/docs/install/html). ## Steps Use the wizard step **Install the widget**, or **Settings → Widget install**. ### Site without login 1. Open **Install manually → HTML** and paste this in the shared layout, just before ``. ``` ``` `YOUR_PROJECT_KEY` is the `data-project` value on that tab. It is also shown under **Settings → Danger zone**. Copy `src` from the tab if your dashboard does not use `https://www.modifee.com/widget.js`. This mode does not use `MODIFEE_SECRET`. 2. Or press **Install automatically**. The pull request is titled "Install Modifee widget" on branch `modifee/install-widget`. The file depends on the repo: | Repo | File edited | Tag | | --- | --- | --- | | Vite, with `index.html` and `package.json` beside `vite.config`, and `react` in dependencies | `index.html` | HTML script above | | Astro, with `src/layouts/Layout.astro`, or exactly one file in `src/layouts`, or only `src/pages/index.astro` | that file | `is:inline` script below | | Flask | `templates/base.html`, `templates/layout.html`, or `app/templates/base.html` | HTML script above | | Django (`manage.py` and `templates/base.html`) | `templates/base.html` | HTML script above | | Rails | `app/views/layouts/application.html.erb` | HTML script above | | Laravel | `resources/views/layouts/app.blade.php` or `resources/views/app.blade.php` | HTML script above | Astro tag, placed just before ``: ``` ``` `YOUR_PROJECT_KEY` is the same key as in the HTML tag. Place the tag just before ``. Vite without React in `package.json` does not get a pull request: "This is a Vite app, but React is not a dependency next to vite.config. Paste the snippet above. No pull request was opened." ### App with login 1. Set **Authentication** to **App with login** and save. 2. Copy **Settings → Client access → Signing secret**. The code block is labeled **MODIFEE_SECRET**. On a host that is not Vercel, the page says "Add this value as the MODIFEE_SECRET environment variable on your host. The agency app signs the logged-in user's email with HMAC-SHA256." On Vercel, connect the project and wait for "MODIFEE_SECRET set on Vercel ✓", then redeploy. See [Signing secret](https://www.modifee.com/docs/vercel/signing-secret) and [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy). 3. Open **Install manually**. The tabs are **Next.js (App Router)**, **Next.js (Pages Router)**, **Flask**, **Django**, **Laravel**, and **Rails**. Flask is below. Next.js is in [Next.js App Router](https://www.modifee.com/docs/install/nextjs-app-router) and [Next.js Pages Router](https://www.modifee.com/docs/install/nextjs-pages-router). ``` import hmac, hashlib, base64, json, time, os def modifee_token(email, name=None): raw = json.dumps( {"email": email, "name": name, "exp": int(time.time()) + 86400}, separators=(",", ":"), ).encode() payload = base64.urlsafe_b64encode(raw).rstrip(b"=").decode() sig = base64.urlsafe_b64encode( hmac.new(os.environ["MODIFEE_SECRET"].encode(), payload.encode(), hashlib.sha256).digest() ).rstrip(b"=").decode() return f"{payload}.{sig}" @app.context_processor def inject_modifee_token(): if not current_user.is_authenticated: return {"modifee_token": None} return { "modifee_token": modifee_token(current_user.email, getattr(current_user, "name", None)), } {# templates/base.html #} {% if current_user.is_authenticated %} {% endif %} ``` `YOUR_PROJECT_KEY` in that block is the key from the tab. The hint is "Pass the token from a context processor. The tag renders only when current_user is authenticated." Then "Store the secret as MODIFEE_SECRET in your server environment." and "Sign the email on the server. The browser only receives the signature." 4. **Install automatically** for Flask templates `templates/base.html`, `templates/layout.html`, or `app/templates/base.html` writes `modifee_identity.py` and this block before ``: ``` """Server-only. Sign the logged-in user's email. Never send MODIFEE_SECRET to the browser. Pass the result into the template as modifee_token, for example from the signed-in user: token = modifee_token(current_user.email, getattr(current_user, "name", None)) """ import base64 import hashlib import hmac import json import os import time def modifee_token(email, name=None): raw = json.dumps( {"email": email, "name": name, "exp": int(time.time()) + 86400}, separators=(",", ":"), ).encode() payload = base64.urlsafe_b64encode(raw).rstrip(b"=").decode() signature = base64.urlsafe_b64encode( hmac.new(os.environ["MODIFEE_SECRET"].encode(), payload.encode(), hashlib.sha256).digest() ).rstrip(b"=").decode() return f"{payload}.{signature}" ``` ``` {% if modifee_token %} {% endif %} ``` The pull request says "Set modifee_token from the signed-in user before rendering the template. Store the secret as MODIFEE_SECRET." If `modifee_identity.py` already exists and differs, install stops with the file path, then `already exists and was left unchanged. Paste the snippet above. No pull request was opened.` Vite, Astro, and other static files get "This site has no server file where a token can be signed. Switch to Site without login to install with one line, or paste the signed-token snippet on your server. No pull request was opened." Django, Laravel, and Rails use the same token shape as Next.js and Flask: base64url JSON `{ email, name, exp }`, then base64url HMAC-SHA256 of that payload with `MODIFEE_SECRET`, joined by `.`. `exp` is the current unix time plus 86400 seconds. The widget attribute is `data-token`. Select the matching tab: ``` import hmac, hashlib, base64, json, time, os def modifee_token(email, name=None): raw = json.dumps( {"email": email, "name": name, "exp": int(time.time()) + 86400}, separators=(",", ":"), ).encode() payload = base64.urlsafe_b64encode(raw).rstrip(b"=").decode() sig = base64.urlsafe_b64encode( hmac.new(os.environ["MODIFEE_SECRET"].encode(), payload.encode(), hashlib.sha256).digest() ).rstrip(b"=").decode() return f"{payload}.{sig}" def modifee_token_context(request): user = getattr(request, "user", None) if user is None or not user.is_authenticated: return {"modifee_token": None} name = user.get_full_name() or None return {"modifee_token": modifee_token(user.email, name)} # settings.py — TEMPLATES[0]["OPTIONS"]["context_processors"] # "myapp.context_processors.modifee_token_context" {# templates/base.html #} {% if user.is_authenticated %} {% endif %} ``` ``` function modifee_token(string $email, ?string $name = null): string { $json = json_encode([ 'email' => $email, 'name' => $name, 'exp' => time() + 86400, ], JSON_UNESCAPED_SLASHES); $payload = rtrim(strtr(base64_encode($json), '+/', '-_'), '='); $sig = rtrim(strtr(base64_encode(hash_hmac('sha256', $payload, env('MODIFEE_SECRET'), true)), '+/', '-_'), '='); return $payload.'.'.$sig; } @auth @endauth ``` ``` # app/helpers/modifee_helper.rb require "base64" require "json" require "openssl" def modifee_token(email, name = nil) payload = Base64.urlsafe_encode64( { email: email, name: name, exp: Time.now.to_i + 86_400 }.to_json, padding: false ) signature = Base64.urlsafe_encode64( OpenSSL::HMAC.digest("SHA256", ENV.fetch("MODIFEE_SECRET"), payload), padding: false ) "#{payload}.#{signature}" end <%# app/views/layouts/application.html.erb %> <% if user_signed_in? %> <% end %> ``` Render that HTML on each request for the signed-in user. Flask, Django, Laravel, and Rails must not cache the full page for a logged-in user. A cached page can send one user's token to someone else. A stack the tabs do not list still signs the same way. Replace `TOKEN` with the signature. Do not put `MODIFEE_SECRET` in the browser. ``` // Your server must generate the token; never put the secret in the browser. // payload = base64url(JSON { email, name, exp }) // token = payload + "." + base64url(HMAC_SHA256(MODIFEE_SECRET, payload)) ``` ## Verify 1. Deploy the page that contains `widget.js` and this project's key. 2. Open **Settings → Widget install**. 3. Press **Check installation**. 4. "Found on the site." and "Widget found on the site." The mark beside **Widget install** turns green. For **App with login**, the tag is in the HTML only for a signed-in response. The checker fetches the site URL without logging in. If the tag is inside an auth block, the check can report the widget missing while a signed-in browser still loads it. Open the site while logged in so the widget can ping. A failed check still leaves the mark yellow. The tooltip is "Widget not found on the site". ## Troubleshooting - "Add a site URL before checking." - `We couldn't find the widget on` the saved site URL. `Paste the snippet just before and check again.` - `The widget on this page belongs to another project.` - `We couldn't reach` the saved site URL. `Connection failed. The widget will be marked installed as soon as it loads on the site.` - `This page is rendered in the browser, so the widget script is not in the HTML we fetched from` the saved site URL. `Open the site after you paste the snippet. We'll mark this done as soon as the widget loads.` - "This repo has more than one Vite app. Paste the snippet above. No pull request was opened." - "Vite is configured, but index.html and package.json are not both next to vite.config. Paste the snippet above. No pull request was opened." - "This repo has more than one Astro site. Paste the snippet above. No pull request was opened." - "This Astro site has several layouts and no src/layouts/Layout.astro. Paste the snippet above. No pull request was opened." - "This Astro site has no layout we can edit safely. Paste the snippet above. No pull request was opened." - "This site has no server file where a token can be signed. Switch to Site without login to install with one line, or paste the signed-token snippet on your server. No pull request was opened." - "MODIFEE_SECRET is only used for App with login." - "Link a Vercel project before setting MODIFEE_SECRET." - Browser console: "Modifee: data-project is required". "Modifee: data-project and data-token are required". - [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing). - [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002) and [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed). - [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy). # Auth methods Choose Site without login or App with login, and see what the client does before a request is accepted. ## Prerequisites - A Modifee project. - The project **Settings** page. The wizard step **Client access** uses **Public site, no login** and **Site with login**. Settings calls the same modes **Site without login** and **App with login**. The default is **Site without login**. ## Steps Open **Settings → Client access**. The description is "How a client proves who they are before opening the widget." The field is **Authentication**. ### Site without login Use this when the site has no login. The client proves who they are with an email and a code. 1. Set **Authentication** to **Site without login**. 2. Set the [access marker](https://www.modifee.com/docs/client-access/access-marker) and [who can request changes](https://www.modifee.com/docs/client-access/allowed-emails). 3. Press **Save**. The install snippet has no `data-token` and does not use `MODIFEE_SECRET`. The button stays hidden until the client opens the marker URL. **Ctrl+Shift+M** on the site shows it during setup. What the client sees, in the widget language (en, fr, es): 1. The launcher. English: "Request a change". 2. **Enter your email**, then **Continue**. 3. An email whose subject is "Your Modifee code:" plus the code. The body says "This code expires in 10 minutes." 4. **Enter the code you received**, then **Verify**. 5. The request screen. **Sign out** ends the session. A session lasts 30 days. ### App with login Use this when the site already has accounts. The server signs the logged-in user's email. Guests do not get a token, so they do not see the widget. There is no email step. 1. Set **Authentication** to **App with login**. 2. Press **Save**. **Signing secret** appears under the card. 3. Install the signed snippet. See [Next.js App Router](https://www.modifee.com/docs/install/nextjs-app-router), [Next.js Pages Router](https://www.modifee.com/docs/install/nextjs-pages-router), or [Other frameworks](https://www.modifee.com/docs/install/other-frameworks). The token is the base64url JSON `{ email, name, exp }`, a `.`, then the base64url HMAC-SHA256 of that base64url string. `exp` is the unix time plus 86400 seconds (24 hours). The HMAC key is `MODIFEE_SECRET`. The same shape is in the install library: ``` // Your server must generate the token; never put the secret in the browser. // payload = base64url(JSON { email, name, exp }) // token = payload + "." + base64url(HMAC_SHA256(MODIFEE_SECRET, payload)) ``` Replace `TOKEN` with that signature. `email` is required. `name` may be omitted. The widget reads `data-token` from the script tag. It does not call your server for the token. `MODIFEE_SECRET` is the project key secret. **Settings → Client access → Signing secret** shows it in the code block labeled **MODIFEE_SECRET**. Modifee stores it encrypted. On the host it is the environment variable `MODIFEE_SECRET`, read only in server code (`process.env.MODIFEE_SECRET` in the Node snippet). On Vercel it is pushed for Production and Preview. See [Signing secret](https://www.modifee.com/docs/vercel/signing-secret). The browser receives the token only. Put the secret in the server environment. A `NEXT_PUBLIC_` variable, a client bundle, or the HTML of a guest page would let anyone sign a token for an allowed email. The page that renders the token must be built per request and must not be cached. See the **App with login** section of the install page for that framework. ## Verify 1. Press **Save** on **Client access**. 2. The mark beside **Client access** is green when at least one email or domain is saved. For **App with login** it also waits until a Vercel project is linked and `MODIFEE_SECRET` has been pushed. See [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails) and [Signing secret](https://www.modifee.com/docs/vercel/signing-secret). 3. Open the site the way a client would. **Site without login**: the marker URL, then the email and the code. **App with login**: a signed-in page, with the widget and no email prompt. ## Troubleshooting - "Choose how clients open the widget." - Yellow **Client access**, tooltip "No authorized email". - Yellow **Client access**, tooltip "Link a Vercel project so the HMAC secret can be pushed". - Yellow **Client access**, tooltip "HMAC secret is not on Vercel yet". - "MODIFEE_SECRET is only used for App with login." - "MODIFEE_SECRET is not set" when the generated signing function runs without the variable. - Browser console: "Modifee: data-project and data-token are required". - "Could not verify your identity. Refresh the page and try again." is [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001). - "That code is incorrect or has expired." is [MDF-AUTH-004](https://www.modifee.com/docs/errors/MDF-AUTH-004). - "Too many attempts. Request a new code." is [MDF-AUTH-005](https://www.modifee.com/docs/errors/MDF-AUTH-005). - "Too many codes requested. Try again in a few minutes." is [MDF-QUOTA-003](https://www.modifee.com/docs/errors/MDF-QUOTA-003). - "This email isn't allowed to request changes on this site." is [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002). See [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails). # Access marker Choose the URL marker that shows the widget on a site without login, and replace the link when it changes. ## Prerequisites - **Authentication** set to **Site without login** (wizard: **Public site, no login**). - **Site URL** saved under **Settings → Connection**, so the client link can be built. **App with login** hides **Access marker**. The widget is shown from `data-token` instead. See [Auth methods](https://www.modifee.com/docs/client-access/auth-methods). ## Steps Open **Settings → Client access**. 1. The field **Access marker** starts as `modifee`. The line under it is "The widget stays hidden until the client opens `/?modifee`", with your marker and an example URL. 2. Type another marker, or press **Generate random**. **Generate random** fills 24 letters and digits. 3. Press **Copy** to copy the full client link. The button then says "Copied". 4. Press **Save**. A marker is 3 to 64 letters, numbers, underscores, or hyphens. The client link is the site URL plus `?` and the marker, for example `https://their-site.com/?modifee`. Send that link. The widget checks the query against the saved marker, removes the marker from the address bar, and keeps the button visible while they browse that tab. **Ctrl+Shift+M** on the site shows the widget too. Use that while you are setting it up. The marker only decides whether the button is visible. Anyone who has the link, or who uses **Ctrl+Shift+M**, can open the widget. Who can send a request is **Who can request changes?**. See [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails). ### Change the marker 1. Edit **Access marker** or press **Generate random**. 2. Press **Save**. 3. Confirm "The old link will stop working. Send the new link to your client." The previous `?marker` no longer unlocks a new visit. Send the new link. A tab that already showed the widget keeps it until that browsing session ends. ## Verify 1. Open the site with no marker. The button stays hidden. 2. Open the copied link. The button appears, and the marker disappears from the URL. 3. Browse to another page in the same tab. The button stays. 4. After a change, the old link leaves the button hidden. The new link shows it. ## Troubleshooting - "Use 3 to 64 letters, numbers, underscores, or hyphens." - "That name is reserved. Choose another marker." Reserved names are `page`, `id`, `q`, `s`, `ref`, `fbclid`, `gclid`, and anything that starts with `utm_`. - **Copy** stays disabled until **Site URL** can build a link. Save the URL under **Settings → Connection**. - The button stays hidden on the plain site URL. That is the marker. Open the client link, or press **Ctrl+Shift+M**. - The widget is visible and the email is rejected. The marker did its job. Add the address under [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails). The message is [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002). - [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing). # Allowed emails Add or remove the people who can request changes, and send a test request from the agency. ## Prerequisites - The project **Settings** page, section **Client access**. - **Authentication** already chosen. The list is used for both **Site without login** and **App with login**. ## Steps The block is **Who can request changes?**. An empty list denies everyone. The note is "Nobody can request changes until you add at least one person. An empty list denies everyone." ### Add someone 1. Press **Add**. 2. Type an email, or a company domain that starts with `@`. The placeholder is `sam@gmail.com or @client.com`. 3. Press **Add** again. The address appears in the list. 4. Press **Save** on **Client access**. `@client.com` allows any email that ends with `@client.com`. A single address allows that address only. Values are stored in lowercase. ### Remove someone 1. Press the × on that person. The button name is "Remove" plus the address. 2. Press **Save**. Until **Save**, the change stays in the form. ### Agency test **Send a test request** is on the project header. It opens the site as the signed-in agency user for 30 minutes. The token is separate from `MODIFEE_SECRET`. The allowlist is skipped for that visit. The widget shows "Test mode — agency" (fr: "Mode test — agence", es: "Modo de prueba — agencia"). The draft is "Change the homepage heading to Welcome". The request appears in **Inbox** with the badge **Test**, on the list and on the request. If **Site URL** is missing, or the last widget check is unreachable, the button opens the hosted test page in the dashboard instead of the site. ## Verify 1. Save at least one address. The empty-list note disappears. 2. The mark beside **Client access** is no longer yellow for "No authorized email". **App with login** can still be yellow until the [signing secret](https://www.modifee.com/docs/vercel/signing-secret) is on Vercel. 3. From the widget, an address on the list gets a code or a signed-in session. An address off the list sees the message below. 4. Press **Send a test request**. The widget shows "Test mode — agency". **Inbox** shows **Test** on that request. ## Troubleshooting The widget shows [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002): - English: "This email isn't allowed to request changes on this site." - French: "Ce courriel n'est pas autorisé à demander des modifications sur ce site." - Spanish: "Este correo no está autorizado a solicitar cambios en este sitio." Add that email, or the company domain, then **Save**. See [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed). - `Invalid email:` followed by the address. - `Invalid domain:` followed by the domain. - The domain, then "is a public email domain. Add a specific address, or a company domain such as @client.com." - On save, the same case uses "Allow a client address or their company domain, such as @client.com." - "That person is already on the list." - Yellow **Client access**, tooltip "No authorized email". - A test request that never opens the site: save **Site URL**, and fix a widget check that says the site is unreachable. [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing). # Vercel integration Install the Vercel integration, choose the project, and grant access when that project is missing from the list. ## Prerequisites - A Modifee project whose repository is on GitHub. - Access to the Vercel team that owns the deployment. You can start from the project **Settings** page (**Previews**, or **Client access → Signing secret** when **Authentication** is **App with login**), or from workspace **Settings → Integrations**. ## Steps ### Install 1. Press **Connect Vercel**. 2. With no Vercel account stored yet, Modifee sends you to Vercel to install the integration. Approve it for the account or team that owns the project. 3. You come back to the dashboard. The account line is "Vercel account ·" the account name, with the badge **Connected**. On **Settings → Integrations** the card **Vercel** uses the same badge. The note there is "Connected accounts can create preview bypass secrets for linked projects." A connection that is already stored does not start install again. **Connect Vercel**, **Reconnect**, and **Don't see your project? Grant access in Vercel** open the installed integration on Vercel. That page is where **Project Access** is edited. Notices you can see on return: - "Connected to Vercel." - "Connected to Vercel · previews accessible to your clients ✓" - "Connected to Vercel. Choose the Vercel project for this repo." ### Choose the project The list is the projects this integration can already see. It is loaded from Vercel, not from a saved copy. If exactly one granted project is this GitHub repo, Modifee links it and pushes `MODIFEE_SECRET` without asking you to pick. More than one match leaves the matching names in **Vercel project**. On **Signing secret**: 1. Open **Vercel project**. The placeholder is "Choose a Vercel project". 2. Press **Connect Vercel**. If a project is already linked, the button is **Switch to** plus the project name. The current row says "Linked to Vercel project:" the name, and **Change**. 3. The toast is "Connected to Vercel project" plus the name. The button then reads **Connected ✓**. On **Previews**, under **Access** and **Automatic (recommended)**: 1. Open **Vercel project**. The placeholder is "Choose a project". 2. Press **Link project**. If that Vercel project is not connected to this GitHub repo, Modifee asks "This Vercel project is not connected to" the `owner/repo` name, then "Link it anyway?" Press **Link anyway** to keep it. The card can also show "This Vercel project is not connected to" that same name. Linking pushes `MODIFEE_SECRET` when the project has an API key. See [Signing secret](https://www.modifee.com/docs/vercel/signing-secret). ### A project that is not in the list The integration only lists projects it was granted. 1. Press **Don't see your project? Grant access in Vercel**, or **Add this project's access in Vercel** under "Your Vercel integration only has access to some projects." 2. On Vercel, open **Project Access** for the Modifee installation and include the project. 3. Back on **Signing secret**, press **Refresh**. "None of your granted Vercel projects use" the `owner/repo` name means the granted list has projects, and none of them is this GitHub repo. Grant this project, or link another and confirm **Link anyway**. ## Permissions The Vercel consent screen groups them like this. Read: - **Installation** - **Deployments**. Reads the production deployment so Modifee can tell whether `MODIFEE_SECRET` is live. Read and Write: - **Projects**. Lists projects, links one, and creates or revokes the bypass secret labeled "Modifee client previews". Missing: "The Modifee Vercel integration is missing the Projects read-write scope." - **Integration-owned Project Environment Variables**. Writes `MODIFEE_SECRET` on Production and Preview. Missing: "The Vercel integration cannot read or write environment variables. Add the Environment Variables permission on the Modifee integration, then reconnect Vercel." **Deployments** moves to Read and Write when the redeploy permission is included. That is what [Redeploy now](https://www.modifee.com/docs/vercel/redeploy) uses. Without it, Vercel returns 403 and the banner says "Redeploy from Vercel or push a commit." The server reason is "Missing deployment permission." An installation that is already connected does not pick up a new permission by itself. In Vercel, open **Integrations → modifee → Manage** and approve the permission update. Then press **Redeploy now** again. Les libellés peuvent changer côté Vercel. ## Why Modifee needs a bypass secret Vercel Authentication sends anyone who opens a preview to a Vercel login page. Your client must never see that page. A Protection Bypass for Automation secret lets Modifee open the preview for them. Needed once per Vercel project. Takes 30 seconds. 1. **Open Deployment Protection in Vercel.** The page is `https://vercel.com/{team}/{project}/settings/deployment-protection`. It opens in a new tab from **Settings → Previews**. 2. **Scroll to Protection Bypass for Automation → Add Secret → Save.** ![Protection Bypass for Automation in Vercel: Add Secret, then Save](https://www.modifee.com/images/vercel-protection-bypass.svg) 3. **Copy the secret and paste it here.** Back on the Modifee tab, **Settings → Previews** looks for the secret on its own. You can also paste it into the field. ## Verify 1. **Settings → Integrations** shows **Connected** on **Vercel**. 2. **Signing secret** shows "Linked to Vercel project:" and the project name. 3. The project you need is in **Vercel project** after **Refresh**. Preview bypass setup is [Protected previews](https://www.modifee.com/docs/vercel/protected-previews). ## Troubleshooting - "Vercel integration is not configured." - "This Vercel connection link expired. Start again from Settings." - "Vercel did not return an authorization code." - "Could not connect Vercel." - "Could not connect Vercel to this project." - "Vercel connection lost, reconnect" - "No Vercel account connected." - "No Vercel project is linked to this repository yet." - "Choose a Vercel project." - "That Vercel project is not on the connected account." - "Could not reach Vercel." - "The Modifee Vercel integration is missing the Projects read-write scope." - "The Vercel integration cannot read or write environment variables. Add the Environment Variables permission on the Modifee integration, then reconnect Vercel." - **Disconnect** on **Previews** or on **Settings → Integrations** revokes the "Modifee client previews" bypass Modifee created. Other bypass secrets stay. The toast is "Disconnected". # Signing secret Store MODIFEE_SECRET, push it to Vercel Production and Preview, and regenerate it when the value must change. ## Prerequisites - **Settings → Client access → Authentication** set to **App with login**, then **Save**. **Signing secret** is hidden for **Site without login**. - An API key for the project. **Settings → Danger zone** shows "No active key." until one exists. Projects get a key when they are created. See [Auth methods](https://www.modifee.com/docs/client-access/auth-methods) for the token shape. The host reads the variable in server code only. ## Steps Open **Settings → Client access → Signing secret**. The code block is labeled **MODIFEE_SECRET**. That value is the project key secret. The agency app signs the logged-in user's email with HMAC-SHA256. The browser receives the token, not this value. ### On Vercel 1. [Connect Vercel](https://www.modifee.com/docs/vercel/integration) and link the project. The line is "Linked to Vercel project:" and the project name. 2. Linking writes `MODIFEE_SECRET` for Production and Preview. The status becomes "MODIFEE_SECRET set on Vercel ✓" once the variable is on production. "Last push:" shows the date of that write. 3. That checkmark means the variable is stored. The running deployment still has the previous environment until you redeploy. The banner under the status is the signal. Follow [Redeploy](https://www.modifee.com/docs/vercel/redeploy). The sentence under the status is "This is the HMAC secret stored for this project. Regenerating updates Vercel for Production and Preview." Status lines: - "MODIFEE_SECRET set on Vercel ✓" — the variable is on production. A redeploy can still be required. See [Redeploy](https://www.modifee.com/docs/vercel/redeploy). - "MODIFEE_SECRET is not on Vercel yet." - "Vercel not connected — connect or add it manually" - "This project is not linked to a Vercel project." - "Could not check MODIFEE_SECRET on Vercel." ### On another host When Vercel is not connected, or the project is not linked, the page says "Add this value as the MODIFEE_SECRET environment variable on your host. The agency app signs the logged-in user's email with HMAC-SHA256." Copy the code block into the server environment. Redeploy that host so the process sees it. Press **Connect Vercel** when you want the push instead. ### Regenerate Press **Regenerate**. There is no extra confirm. What changes: - Modifee replaces the stored secret immediately. Tokens signed with the previous value fail. - The code block shows the new value. - When a Vercel project is linked, Production and Preview are updated to that value. "Last push:" changes. The redeploy banner appears, because the running deployment still has the old value. See [Redeploy](https://www.modifee.com/docs/vercel/redeploy). - When no Vercel project is linked, the status is "This project is not linked to a Vercel project." Copy the new value onto the host yourself. The log reason is "project is not linked to a Vercel project", or "workspace has no Vercel connection". - If the stored secret changed and Vercel rejected the write, the error is "Secret regenerated, but Vercel was not updated." followed by the Vercel message. The host still has the old value until a later push succeeds. Every install that signs with `MODIFEE_SECRET` must use the new value. Old HTML that still carries a token signed with the previous secret is rejected. ## Verify 1. The code block **MODIFEE_SECRET** has a value. 2. On Vercel, the status is "MODIFEE_SECRET set on Vercel ✓" with "Last push:". The banner asks for a redeploy until production has deployed since that push. 3. After [Redeploy](https://www.modifee.com/docs/vercel/redeploy), a signed-in page on the new deployment opens the widget. 4. The mark beside **Client access** is green for the secret once the push time is stored. An empty allowlist can still leave it yellow. See [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails). ## Troubleshooting - "This project has no API key yet." - "Generate an API key before setting MODIFEE_SECRET." - "Generate an API key before regenerating the signing secret." - "Could not read this project's secret." - "MODIFEE_SECRET is only used for App with login." - "Link a Vercel project before setting MODIFEE_SECRET." - "This project is not linked to a Vercel project we can update." - "MODIFEE_SECRET already exists on Vercel." - "Vercel refused to set MODIFEE_SECRET." - "Could not reach Vercel." - "Secret regenerated, but Vercel was not updated." - "The Vercel integration cannot read or write environment variables. Add the Environment Variables permission on the Modifee integration, then reconnect Vercel." - "The Modifee Vercel integration is missing the Projects read-write scope." - Yellow **Client access**, tooltip "Link a Vercel project so the HMAC secret can be pushed". - Yellow **Client access**, tooltip "HMAC secret is not on Vercel yet". - The widget loads and then says "Could not verify your identity. Refresh the page and try again." The deployment is still signing with the previous secret, or the token is older than 24 hours. Redeploy, then sign in again. [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001). [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy). # Redeploy Redeploy production after MODIFEE_SECRET is pushed so the running site picks up the new value. ## Prerequisites - **App with login**, with a Vercel project linked. See [Signing secret](https://www.modifee.com/docs/vercel/signing-secret). - `MODIFEE_SECRET` already written on Vercel. The status is "MODIFEE_SECRET set on Vercel ✓". The banner is what asks for the redeploy. - At least one production deployment on that Vercel project. ## Steps Vercel applies environment variables on the next deployment. Writing `MODIFEE_SECRET` does not restart the current one. Until production is deployed again, the site keeps signing with the previous value, and Modifee checks tokens against the new one. The status line can already say "MODIFEE_SECRET set on Vercel ✓". That means the variable is stored. The banner under **Signing secret** says "The secret is on Vercel, but it only applies on the next deployment." The shorter line is "Redeploy required — the secret applies on the next deployment." 1. Press **Redeploy now**. The label becomes "Deploying…". 2. Modifee starts a new Production deployment from the latest production deployment. Preview already has the variable. A preview deployment picks it up the next time that preview is deployed. This button does not redeploy previews. 3. Wait on the banner. It checks the deployment every few seconds. **Open in Vercel** opens that project's deployments. ### Permission missing (403) If Vercel returns 403, the banner says "Redeploy from Vercel or push a commit." The server reason is "Missing deployment permission." 1. Press **Update integration permissions**. That opens the installed Modifee integration on Vercel. 2. Allow **Deployments** for the integration. 3. Return to **Signing secret** and press **Redeploy now** again. You can also redeploy from Vercel, or push a commit, as the banner says. A production deployment whose start time is after the last push counts as deployed. ## Verify The banner turns green and says "Deployed ✓ — the widget is live". That line means the latest READY production deployment started at or after the last `MODIFEE_SECRET` push. The status line "MODIFEE_SECRET set on Vercel ✓" can show before this, as soon as the variable is stored. Open the production site while signed in. The widget should accept the token. A token signed before **Regenerate** still fails. ## Troubleshooting - "Redeploy from Vercel or push a commit." with **Update integration permissions**. The Deployments permission is missing (HTTP 403, "Missing deployment permission."). - "The deployment failed." The deployment `readyState` was `ERROR` or `CANCELED`, or Modifee could not start one. - "There is no production deployment to redeploy." The banner still shows "The deployment failed." Create a production deployment on Vercel, then press **Redeploy now**. - "This project is not linked to a Vercel project we can update." - "That Vercel project was not found." - The banner stays on "The secret is on Vercel, but it only applies on the next deployment." Production has not finished a deployment since the push. Press **Redeploy now** or **Open in Vercel**. - [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy). # Protected previews Open Vercel-protected preview deployments for clients, and leave other hosts on GitHub detection. ## Prerequisites - The project **Settings** page, section **Previews**. - **Show previews to clients** turned on. The off state says "Previews disabled" and "Clients won't see a preview link before changes are merged." Preview URLs are detected from GitHub. Connecting Vercel is for Deployment Protection, and for [MODIFEE_SECRET](https://www.modifee.com/docs/vercel/signing-secret) when you use **App with login**. ## Steps Open **Settings → Previews**. The description is "Preview links clients see before a change is merged." ### What Modifee detected **Detection** says "Detected automatically from GitHub." - Vercel: "Hosted on Vercel ·" the project name. - Another known host: "Hosted on" the host name, then "· No setup needed". - Nothing yet: "No preview detected yet". **Last preview** links to the latest preview URL. Before any request stores one, the line is "Waiting for the first request to confirm." GitHub deployments decide the host: a Vercel deployment or a `Preview` environment, a Heroku deployment or a review app, or root files `vercel.json`, `next.config.*`, `app.json`, or `Procfile`. Netlify, Render, Cloudflare Pages, and other hosts use the same GitHub preview URL. **Settings → Integrations** says "Only needed if your previews are protected by Vercel. Modifee detects previews from GitHub, so Netlify, Render, Cloudflare Pages and others work with no setup." The onboarding step **Previews** uses the same detection: - "Connected to Vercel ·" the project name, or "Connected to Vercel" - "Hosted on Vercel." - "Hosted on Heroku. Clients open the preview link from GitHub." - "Hosted on Netlify. Remove password protection if clients cannot open the preview." - "Hosted on" the host name, then ". Clients open the preview link from GitHub." - "We'll detect your host from your first pull request." ### Vercel Deployment Protection When the preview responds like a login wall, the banner is **Action needed**: "Previews are protected by Vercel. Connect Vercel or add a bypass secret so clients can open them." **Connect Vercel** starts [the integration](https://www.modifee.com/docs/vercel/integration). **Access** offers two cards: - **Automatic (recommended)**. "Modifee creates the bypass secret through your Vercel connection." The secret Vercel stores is labeled "Modifee client previews". The badge **Active** means that integration secret is the one in use. - **Manual secret**. "Paste a Protection Bypass secret from Vercel." The field is **Protection bypass secret**. The hint is "Vercel → Project → Settings → Deployment Protection → Protection Bypass for Automation." Press **Save secret**. A saved secret shows "Bypass secret · ••••••••", the badge **Set**, **Replace**, and **Remove**. On the client preview link, Modifee adds Vercel's protection bypass and sets the bypass cookie. The client opens the preview without a Vercel account. After a save, "Previews are now accessible to your clients ✓" means the check got through. "Secret saved, but the preview still requires a login. Double-check the secret in Vercel." means the secret is stored and the preview still looks protected. **Use automatic secret** replaces a manual secret with one Modifee creates. **Disconnect** revokes the "Modifee client previews" secret. See [Vercel integration](https://www.modifee.com/docs/vercel/integration). ### Other hosts Leave **Access** unused. The detection line "Hosted on" the host, then "· No setup needed", is the setup. Clients open the preview URL from GitHub. If Netlify password protection is on, the onboarding line tells you to remove it. ## The Previews mark The mark beside **Previews** is separate from the banner. Green ("Complete") when any of these is true: - **Show previews to clients** is off. - The host is known, and it is not a protected Vercel preview missing a bypass secret, and the last preview check did not fail. Yellow, with the tooltip as the reason: - "Previews are protected. Connect Vercel or add a bypass secret so clients can open them." The host is Vercel, the preview is protected, and no bypass secret is stored. The banner title in that case is **Action needed**. - "No preview host detected. Add where this site is hosted." - "The last preview check failed. Run it again from the project." A known host that is not Vercel stays green without a bypass secret. A Vercel preview that is not protected stays green without one. A protected Vercel preview with a bypass secret stored keeps the mark green. **Access** can still show "Secret saved, but the preview still requires a login. Double-check the secret in Vercel." ## Verify 1. Turn **Show previews to clients** on and press **Save**. 2. For Vercel Authentication, connect or paste the bypass, then open a client preview link. It should load without a Vercel login. 3. The mark beside **Previews** is green, or the yellow tooltip matches one of the three reasons above. 4. For Netlify, Render, Cloudflare Pages, or another GitHub-detected host, confirm "No setup needed" and open the preview from a request. ## Troubleshooting - "Previews unavailable" plus the error under it: "Vercel connection lost, reconnect", a list error, or "Vercel refused to create the bypass secret. Paste one manually below." - "Secret saved, but the preview still requires a login. Double-check the secret in Vercel." - "Paste the Vercel protection bypass secret." - "Protection bypass secret is too long." - "This project is not hosted on Vercel." - "Could not store the protection bypass secret." - "The Modifee Vercel integration is missing the Projects read-write scope." - "No Vercel account connected." - "No Vercel project is linked to this repository yet." - [Previews](https://www.modifee.com/docs/troubleshooting/previews). # For clients How to ask for a site change in the widget, review the preview, and read the messages you may see. This page is for the person who uses the site. Your agency can send it to you. The widget follows your browser language: English, French, or Spanish. ## Prerequisites - The link your agency sent you. It includes a short marker so the change button appears. The usual marker is `modifee`. - The email address your agency allowed, if the site asks you to sign in inside the widget. ## Steps 1. Open the link. On the site, press **Request a change**. In French that button is **Demander un changement**. In Spanish it is **Solicitar un cambio**. If you do not see it, open the link again. On a site where you already sign in, the button is there after you are signed in. 2. If the site has no login of its own, the widget asks **Enter your email**, then **Continue**. Open the email. The subject is **Your Modifee code:** followed by the code. The message says "This code expires in 10 minutes." Enter the code and press **Verify**. In French: **Entrez votre courriel**, **Continuer**, **Votre code Modifee :**, **Entrez le code reçu**, **Vérifier**. 3. The empty screen says "A change to make on your site?" and "Describe it in a few words. You'll get a preview to approve before it goes live." Write three things: the page, the place on that page, and the new content. The hint under the box says "Be specific: the page, the spot, and the new content." In French: "Soyez précis : la page, l'endroit, le nouveau contenu." 4. Three shortcuts fill the box for you. They do not send the message. Press **Send** when the text is right. - English: **Edit some text**, **Change an image**, **Add a section** - French: **Modifier un texte**, **Changer une image**, **Ajouter une section** - Spanish: **Modificar un texto**, **Cambiar una imagen**, **Añadir una sección** 5. To add a picture, press **Attach** (**Joindre** / **Adjuntar**). Then **Choose from library** or **Take a photo**. Use a PNG, JPEG, or WebP image, up to 5 MB. 6. After you send, the widget says "We're preparing your change…" and "This can take a few minutes." In French: "Nous préparons votre changement…" and "Cela peut prendre quelques minutes." 7. When a preview is ready, the title is **Your preview is ready** and the text is "Take a look before it goes live." Press **View preview**. If it is right, press **Looks good**. If something is off, press **Adjust** and write what to change. The box says "What should we adjust?" 8. After **Looks good**, one of two messages appears. "Thanks! Your change is being published automatically." means it is going live on its own. `Thanks! {team} will put it live.` means the team still has to publish it. The team name replaces the placeholder. 9. When it is published, the widget says **It's live!** and "Does this cover what you asked for?" Press **Yes** or **Not quite**. **Not quite** asks "What still needs to change?" In French the live line is **C'est en ligne !** and the buttons are **Oui** and **Pas tout à fait**. ## Verify You can open the preview, and after you press **Looks good** the widget either says the change is being published or that the team will put it live. When it is on the site, the status is **Live** (**En ligne** / **En línea**). ## Troubleshooting The widget shows a short message. Here is what to do. - "This email isn't allowed to request changes on this site." Use the email your agency added, or ask them to add yours. French: "Ce courriel n'est pas autorisé à demander des modifications sur ce site." See [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002). - "That code is incorrect or has expired." Ask for a new code. "Too many attempts. Request a new code." means the same. "Too many codes requested. Try again in a few minutes." means wait, then ask again. - "We couldn't upload that image. Try again or use a different file." Use a PNG, JPEG, or WebP under 5 MB. See [MDF-WIDGET-001](https://www.modifee.com/docs/errors/MDF-WIDGET-001). - "This preview couldn't be built. Your team has been notified." Wait. The team sees it on their side. - "For further adjustments, the team will get back to you." The included tweaks for this change are used up. Write a new request, or wait for the team. See [MDF-REQ-004](https://www.modifee.com/docs/errors/MDF-REQ-004). - "We can't reach the team right now. Try again in a few minutes." Check the connection and try again. See [MDF-WIDGET-005](https://www.modifee.com/docs/errors/MDF-WIDGET-005). - A quote appears with **Accept** and **Decline** (**Accepter** and **Refuser**). That change is larger than a normal edit. Accepting starts the work. Declining asks **Why? (optional)** and then **Decline quote**. If it expires, the widget says "This quote is no longer valid. Write to us to update it." - The team closed it: the team name, then "closed this request without publishing it." In French: "a fermé cette demande sans la mettre en ligne." - `Problem — {team} has been notified.` You do not need to resend. The team will look. The team name replaces the placeholder. # Voice dictation Dictate a widget request into the text box, and how that recording is billed. ## Prerequisites - The widget is open. See [For clients](https://www.modifee.com/docs/widget/for-clients). - The browser can record `audio/webm` with Opus, or `audio/mp4`, and it exposes the microphone. ## Steps 1. Press the microphone. Its name is **Dictate**. In French it is **Dicter**. In Spanish it is **Dictar**. 2. Speak. Recording stops at 2 minutes. 3. While the audio is sent, the box says **Transcribing…** (**Transcription…** / **Transcripción…**). 4. The text is added to the draft. Read it, edit it, then press **Send**. Dictation does not send the request. The recording is not stored. Only the text is added to the draft. Transcription is included. Its cost is counted in **AI spend this month**. Nothing else to configure. ## Verify The spoken words appear in the text box, and the request is still unsent until you press **Send**. On the project overview, **AI spend this month** includes this cost. Dictation does not deduct a credit by itself. Credits are charged when an agent run finishes. See [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits). ## Troubleshooting - The microphone button is missing. The browser cannot record, or it has no microphone API. Typing still works. The button stays hidden in that case. - "Allow the microphone in your browser to dictate." The site was blocked from the microphone. Allow it for this site, then press **Dictate** again. See [MDF-WIDGET-004](https://www.modifee.com/docs/errors/MDF-WIDGET-004). - "Transcription failed. Try again." Type the request, or try again. See [MDF-WIDGET-002](https://www.modifee.com/docs/errors/MDF-WIDGET-002). - Each client can transcribe 30 times per hour on a project. Past that, the widget shows the same "Transcription failed. Try again." message. # Inbox What each request status asks you to do, and what the Test badge means. ## Prerequisites - A project with the widget installed. A request appears after the client presses **Send**, or after you press **Send a test request**. ## Steps Open **Inbox**. The filters are **Needs you**, **Quote sent**, **Quote declined**, **Failed**, **In progress**, **Done**, and **All**. **Needs you** is the default. The status label is what the dashboard shows. Here is what it asks of you. - **Needs a quote**. The change is held. Open it and send a quote. It is in **Needs you**. On Home the line is "Quote to send". See [Quotes and merges](https://www.modifee.com/docs/agency/quotes-and-merges). - **Quote sent**. The client has the quote. It stays out of **Needs you** until it expires (**Quote expired**) or has had no answer for 3 days. That line is "Quote awaiting response (3 days)". - **Quote declined**. The client refused. It is under **Quote declined**. - **Triage**. Classification is still running. **In progress**. Nothing to merge yet. - **Queued**. A run is lined up. **In progress**. - **Agent running**. The coding agent is working. **In progress**. - **Building preview**. A pull request exists and the preview is building. **In progress**. - **Waiting on client**. The preview is ready. The client should press **Looks good** or **Adjust**. This is **In progress**. It is also in **Needs you** when Autopilot is **Off**, or when the request is marked **Review required**. - **No preview**. There is nothing for the client to open. **Needs you**. - **Needs your merge**. The client approved, or a merge is already in progress. Both stored states use this label. Press **Approve & merge**. **Needs you**. On Home the line is "Needs your merge". - **Merged**. Published. **Done**. - **Rejected**. Closed without merging. **Done**. - **Failed**. The run did not finish. **Failed**, and also **Done**. Home lists it in red, not in the yellow waiting list. Press **Retry** or **Reject**. A request that needs a person, whatever its status, is included in **Needs you**. Home then says "Needs you" when none of the more specific lines above apply. Rows you can handle together are **Waiting on client** and **No preview** when the pull request changes 3 files or fewer. Select them and press **Approve & merge** or **Reject**. A row that does not qualify says "Only preview-ready requests that change 3 files or fewer can be handled together." If the file count did not load: "Could not count the changed files." If it is over 3 files, the note is "This diff touches" the count, then "files." ### Test badge A test request shows the badge **Test** on the row. It was opened from **Send a test request**. It skips the allowlist and expires with the test session. It uses the same statuses as a client request. See [Allowed emails](https://www.modifee.com/docs/client-access/allowed-emails). ## Verify **Needs you** contains quotes to send, merges waiting on you, requests with no preview, previews that Autopilot will not ship, expired or reminded quotes, and anything flagged for a person. **In progress** contains triage, the queue, the agent, the preview build, and previews waiting on the client. ## Troubleshooting - **Approve & merge** is disabled. The tooltip is one of: "This request is already closed." "Preview not ready yet." "Review required — merge on GitHub." "No pull request to merge." - **Retry** is disabled with "Only failed requests can be retried." - A **Review required** badge lists the reasons, including a line that starts with "Protected path:" or "Deleted file:". See [Guardrails](https://www.modifee.com/docs/agency/guardrails). # Quotes and merges Send a quote, see what the client gets, then merge, retry, or reject. ## Prerequisites - The request is open from the **Inbox**. - A quote is available when the status is **Needs a quote**. - A merge needs a pull request. **Retry** needs the status **Failed**. ## Steps ### Send a quote 1. On a **Needs a quote** request, the form is **Quote for the client**. 2. **Amount** is optional. The hint is "Optional. Currency:" and the workspace currency. Leave it blank to send no price. 3. **Timing** is optional. The placeholder is "2-3 business days". 4. **Note to the client** is required. The placeholder is "What this covers". 5. **Show the amount to the client** is on by default. Turn it off to hide the price. 6. Press **Send quote to client**. The toast is "Quote sent". The status becomes **Quote sent**, and the quote state is **Pending**. The quote stays valid for **Quote validity (days)** on the project. The default is 14. See [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits). On the same menu (the **…** button) you can skip the quote: - **Run the agent anyway**. The toast is "Agent queued". - **Mark as handled outside Modifee**. The toast is "Marked as handled". ### What the client sees The widget title is **Quote**. In French it is **Devis**. In Spanish it is **Presupuesto**. They see the note, the timing under **Timing** (**Délai** / **Plazo**), and the amount when the switch was on. The buttons are **Accept** and **Decline**. - **Accept** queues the agent. The widget says "Thanks —" the team name "is starting on this." French: "Merci —" the team name "s'en occupe." The dashboard state becomes **Accepted**. - **Decline** asks **Why? (optional)**, then **Decline quote**. The widget says "Understood." and the team name "has your answer." The dashboard state becomes **Declined** and the request status is **Quote declined**. - When the quote expires, the widget says "This quote is no longer valid. Write to us to update it." The dashboard state is **Expired**, and the inbox line is "Quote expired". - After 3 days with no answer, the client is reminded: the team name "is still waiting on your answer to this quote." The inbox line is "Quote awaiting response (3 days)". ### Merge Press **Approve & merge**. The dialog title is the same. - After the client has approved, the text is "Squash-merge this pull request into the default branch." - Before that, it is "The client hasn't approved yet. Merge anyway?" - When the pull request changes more than 5 files, it adds "This diff touches" the count, then "files." - If the file count did not load, it adds "The file count could not be loaded." Confirm **Approve & merge**. The toast is "Merged". The status becomes **Merged**. The widget says **It's live!** The key `a` opens the same merge, unless you are typing in a field. `r` opens **Reply**. **Reply to the client** says "This message is emailed to the client." The toast is "Reply sent". Autopilot can merge an eligible change after **Looks good** without this button. See [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits). ### Retry **Retry** is enabled only when the status is **Failed**. Otherwise the reason is "Only failed requests can be retried." The dialog is **Retry this request**. The text is "Start the agent again. Extra context is added to this attempt only." The box placeholder is "Add context for the agent (optional)". Confirm **Retry**. The toast is "Retry started". ### Reject **Reject** opens **Reject this request**. The text is "Close it without merging. An optional note is sent to the client." The placeholder is "Message to the client (optional)". Confirm **Reject**. The toast is "Rejected". The widget then says the team name "closed this request without publishing it." **Reject** and **Reply** are disabled on a closed request with "This request is already closed." ## Verify A sent quote shows **Pending** until the client acts. **Accept** moves the request forward and shows **Accepted**. A merge ends on **Merged**. A reject ends on **Rejected**. A retry leaves **Failed**. ## Troubleshooting - **Approve & merge** stays disabled. Read the tooltip: "This request is already closed." "Preview not ready yet." "Review required — merge on GitHub." "No pull request to merge." - **Review required** with a "Protected path:" or "Deleted file:" line will not merge from this button. Merge that pull request on GitHub, or change the request so it no longer touches those files. See [Guardrails](https://www.modifee.com/docs/agency/guardrails). - The client says the quote is no longer valid. Send a new quote. The old one is **Expired**. # Autopilot and limits The Autopilot and limits settings, their defaults, and the plan's credits. ## Prerequisites - The project is open. The section is **Settings → Autopilot and limits**. The same card is in the setup wizard. ## Steps The card says "One setting for what can ship after the client approves. Protected files always wait for you." Pick one mode. **Standard** is marked **Recommended**. A new project is stored as **Aggressive**, so that choice is already selected and the **Advanced** disclosure is open. - **Off**. "Every change waits for you." Nothing auto-merges. You press **Approve & merge** after the client approves. - **Safe**. "Text, styles, and links." Only a trivial change can auto-merge. - **Standard**. "Also new pages, long copy, and small UI additions." Trivial and standard changes can auto-merge. - **Aggressive**. "Same scope as Standard, with a higher file and line cap." Shown under **Advanced**. After the client presses **Looks good**, an eligible change is squash-merged. These always wait for you, in every mode: - A protected path. The request shows "Protected path:" and the path. - A deleted file. The request shows "Deleted file:" and the filename. - A change over the file or line cap for that mode. - More than **Max auto-merges per day** already shipped that day. - A preview that is not on the latest commit, or a request with no pull request. Caps used when deciding a merge: | Mode | Files | Lines in existing files | Lines in new files | | --- | --- | --- | --- | | Safe | 5 | 200 | 300 | | Standard | 8 | 200 | 1500 | | Aggressive | 12 | 400 | 3000 | **Off** uses the Safe caps for size checks and still does not ship. The other fields, and the values a new project starts with: - **Max auto-merges per day**. Default 10. Allowed 1 to 100. - **Quote validity (days)**. Default 14. Allowed 1 to 90. This is how long a sent quote stays valid. - **Max spend per run (USD)**. Default 1.00. Allowed 0.25 to 5. This caps what one agent run may cost. - **Max duration (minutes)**. Default 10. Allowed 2 to 20. - **Monthly request cap**. Empty by default, placeholder **No cap**. The hint is "Limits how many requests this client can send per month." Leave it empty for no cap. A value must be a positive whole number. Saving anything else returns "Monthly cap must be a positive whole number, or empty." The cap counts non-test requests created on this project since the start of the UTC month. A new conversation still open from the last 30 minutes counts too, until it becomes a request. Continuing that same conversation does not count again. An adjustment on an existing request does not count. Test requests do not count. When the cap is already reached, the widget refuses a new request and says "You've reached this month's request limit. Your team can raise it." French: "Vous avez atteint la limite de demandes de ce mois. Votre équipe peut l'augmenter." The widget shows that sentence in the client's language, then the code [MDF-PLAN-004](https://www.modifee.com/docs/errors/MDF-PLAN-004), the same way it shows [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002) next to the not-allowed sentence. Press **Save** on the card. ### Requests this month and plan credits The project overview shows **Requests this month**. That count is separate from **Monthly request cap**. Beside it, **AI spend this month** is the summed cost of usage on that project, including dictation. The plan allowance is credits, under **Settings → Plan & usage**, section **Credits**. | Plan | Included credits each month | | --- | --- | | Free | 15 | | Beta | 150 | | Starter | 150 | | Studio | 600 | | Agency | 2000 | The page says "Small edits use 1 credit, bigger changes like new pages use more." A finished agent run costs at least 1 credit. Paid plans (Starter, Studio, Agency) can go over the included amount at $0.60 per extra credit, and unused included credits roll over for one month. Free and Beta do not. The line is "This plan does not bill extra credits. Requests wait until credits are available." **Included remaining**, **Rollover**, and **Overage this period** are on that page. **Monthly spend cap (USD)** starts at 100. Clear the field and press **Save cap** to remove it. An empty field means no cap. The placeholder is **No cap**. ## Verify The selected mode matches what you saved. After a client presses **Looks good** on a small text change, **Safe**, **Standard**, and **Aggressive** can move it to **Merged** without **Approve & merge**. **Off** leaves it on **Needs your merge**. **Plan & usage** shows the included credits for the current plan. ## Troubleshooting - The section mark is yellow. The tooltip is one of: "Daily auto-merge limit must be between 1 and 100", "Quote validity must be between 1 and 90 days", "Max spend per run must be between $0.25 and $5", "Max duration must be between 2 and 20 minutes". - Saving the spend field outside 0.25 to 5 returns "Max cost per run must be between $0.25 and $5." - A change stayed on **Needs your merge** with **Review required**. Read the reason list. Protected paths and deleted files do not auto-merge. See [Guardrails](https://www.modifee.com/docs/agency/guardrails). - Home says "No credits left this period" or "Credits are running low". Open **Plan & usage**. See [Health indicators](https://www.modifee.com/docs/agency/health-indicators). # Guardrails Paths the coding agent must not change, the defaults, and how to edit the list. ## Prerequisites - The project exists. Open **Settings → Guardrails**. ## Steps The section says "Globs the coding agent must never modify. Requests that need these files are classified as large." A request that has to change a matching file is held as **Needs a quote**. The classification reason is "The change touches a protected path, so it needs a quote." If a run still produces a protected path or deletes a file, the request is **Review required** and Autopilot will not merge it. The reason lines start with "Protected path:" or "Deleted file:". **Approve & merge** then says "Review required — merge on GitHub." The agent is also told not to write those paths. ### Defaults A new project copies this list, then adds matching folders it finds in the repository (auth, login, session, billing, stripe, checkout, payment, webhook, models, migrations, alembic, and `middleware` files). - `.env*` and `**/.env*` - `.github/**` - `**/*.pem` and `**/*.key` - `package.json`, `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock` - `requirements.txt`, `Pipfile*`, `poetry.lock` - `vercel.json`, `Procfile`, `app.json`, `Dockerfile`, `docker-compose*` - `**/auth/**`, `**/auth.*`, `middleware.*` - `**/login/**`, `**/session*` - `**/billing/**`, `**/stripe/**`, `**/payment*/**`, `**/checkout/**`, `**/webhook*/**` - `prisma/schema.prisma`, `prisma/migrations/**`, `migrations/**`, `alembic/**` - `**/models.py`, `**/db/migrate/**` The section mark stays green. Guardrails are not a setup check. ### Change the list 1. Type a glob. The placeholder is `src/legacy/**`. Press **Add**, or press Enter. 2. Press **Remove** on a line to drop it. The button name is "Remove" plus the path. 3. Press **Save**. 4. **Reset to defaults** rebuilds the list from the built-in paths and the repository tree. 5. **Add AGENTS.md** opens a pull request that adds `AGENTS.md` at the repository root, including the protected paths. After that pull request exists, the button is replaced by **AGENTS.md PR #** and the number. ## Verify A request that needs a protected file lands on **Needs a quote**, or later shows **Review required** with a "Protected path:" line. A text change that does not touch those paths still proceeds under the current Autopilot mode. ## Troubleshooting - Autopilot skipped a change you expected to ship. Open the request and read **Review required**. A protected path or a deleted file always waits. - **Reset to defaults** removed a path you added. Add it again and press **Save**. - The client still sees a quote for a small visual change. The files the agent would edit match a glob on this list. Narrow the glob, or handle that request with a quote. # Health indicators The Home light, and the green or yellow mark on each project Settings section. ## Prerequisites - You are signed in to the dashboard. The light is on **Home** in the sidebar and again at the top of the Home page. ## Steps ### Home The light is green, yellow, or red. Red wins over yellow. The headline counts only the items of that color. - Green, and no items: "All clear. Nothing to do." - Red: "1 problem to fix", or the count plus "problems to fix". - Yellow, with no red item: "1 thing to check", or the count plus "things to check". Up to three lines are links. After that the rest is a plus sign, the number of remaining lines, and "more". That link opens the **Inbox**. Red lines: - A **Failed** request. The line is the project name, then "Agent run failed", unless the failure is **Build failed**, **Pull request conflict**, or **Repository access**. Those three use that exact label after the project name. - The project name, then "preview check failed". - "GitHub disconnected", when the workspace has no GitHub App installation. - "Vercel disconnected", when the workspace has Vercel connections and every one of them is revoked. - "No credits left this period", on Free and Beta, when included credits plus rollover are below 1. - "Spend cap reached", when overage spend is at or over **Monthly spend cap (USD)**. Yellow lines: - A request that is in **Needs you** and is not **Failed**. The line starts with the project name, then "Quote to send", "Needs your merge", "Quote expired", "Quote awaiting response (3 days)", "Needs you", or the status label (**No preview**, **Waiting on client**, **Quote sent**). - "Finish setting up" and the project name, when a Settings section is still yellow. - "Credits are running low", when included credits plus rollover are 20% or less of the plan's included credits, and the red "no credits" case does not apply. - "Spend cap is nearly reached", when overage spend is at least 80% of the cap and still under it. ### Settings marks Each project Settings section has a mark beside the title. Green means **Complete**. Yellow is an exclamation mark. Hover it, or use the button's name, to read the reason. Clicking it focuses the field. There is no red mark on a section. - **Connection**. Yellow: "No repository is linked" or "Site URL must be a valid https address". - **Client access**. Yellow: "No authorized email". On **App with login**, also "Link a Vercel project so the HMAC secret can be pushed" or "HMAC secret is not on Vercel yet". - **Widget install**. Yellow: "Widget not found on the site". - **Previews**. See below. - **Autopilot and limits**. Yellow when a limit is outside its range. The messages are in [Autopilot and limits](https://www.modifee.com/docs/agency/autopilot-and-limits). - **General**. Yellow: "Project name is required". - **Guardrails**. Always green. ### Why Previews stays green before the first preview **Previews** is green when previews are turned off (**Show previews to clients** is off). It is also green when a host is known, the last preview check did not fail, and protected Vercel previews have a bypass secret if they need one. The line "Waiting for the first request to confirm." is only the detection note. It does not turn the mark yellow. No preview has been opened yet, and that is not a failure. The mark turns yellow only for these reasons: - "Previews are protected. Connect Vercel or add a bypass secret so clients can open them." - "No preview host detected. Add where this site is hosted." - "The last preview check failed. Run it again from the project." ## Verify With no failed requests, no waiting work, finished project setup, and credits above the low line, Home says "All clear. Nothing to do." A project that has never had a preview still shows a green **Previews** mark when the host line is filled in and the three yellow reasons above do not apply. ## Troubleshooting - Home is red and the inbox looks quiet. Open the red line. **Failed** requests are listed on Home even though they are not in the yellow **Needs you** wait. They are under the **Failed** filter. - **Previews** is yellow on a site that has not had a request yet. Read the tooltip. "Waiting for the first request to confirm." is not the cause. The usual cause is an unknown host, a failed check, or a protected Vercel preview with no bypass. See [Protected previews](https://www.modifee.com/docs/vercel/protected-previews). - "Finish setting up" stays after you saved. Another section on that project is still yellow. Open **Settings** and read each exclamation mark. # Symptom index Match a symptom to a troubleshooting page, and the error codes that show up most often. ## Symptom The widget, a preview, or a request is stuck, and you need the page that matches what you see. | Symptom | Page | | --- | --- | | The button **Request a change** never appears | [Widget not showing](https://www.modifee.com/docs/troubleshooting/widget-not-showing) | | "This email isn't allowed to request changes on this site." | [Email not allowed](https://www.modifee.com/docs/troubleshooting/email-not-allowed) | | "Could not verify your identity. Refresh the page and try again." on a site with login | [Token errors](https://www.modifee.com/docs/troubleshooting/token-errors) | | **MODIFEE_SECRET is not on Vercel yet.** or **Redeploy now** fails | [Secret and redeploy](https://www.modifee.com/docs/troubleshooting/secret-and-redeploy) | | The client cannot open a preview, or **Previews** is yellow | [Previews](https://www.modifee.com/docs/troubleshooting/previews) | | The request is **Failed**, or no pull request was opened | [Agent and pull request](https://www.modifee.com/docs/troubleshooting/agent-and-pr) | | Checkout or **Manage billing** fails, or the widget says the monthly request limit | [Billing and plan](https://www.modifee.com/docs/troubleshooting/billing-and-plan) | ## Frequent error codes Each code has a page under `/docs/errors/` with a cause and a fix. - [MDF-AUTH-001](https://www.modifee.com/docs/errors/MDF-AUTH-001) — "You need to sign in." The widget shows "Could not verify your identity. Refresh the page and try again." - [MDF-AUTH-002](https://www.modifee.com/docs/errors/MDF-AUTH-002) — "This email isn't allowed to request changes on this site." - [MDF-AUTH-004](https://www.modifee.com/docs/errors/MDF-AUTH-004) — "That code is incorrect or has expired." - [MDF-QUOTA-001](https://www.modifee.com/docs/errors/MDF-QUOTA-001) — credits or the spend cap. The widget says "Request received — your team has been notified and will process it shortly." - [MDF-QUOTA-002](https://www.modifee.com/docs/errors/MDF-QUOTA-002) — "Too many requests. Try again in a moment." The widget says "Too many messages. Try again in a few minutes." - [MDF-WIDGET-001](https://www.modifee.com/docs/errors/MDF-WIDGET-001) — "That file could not be attached." - [MDF-WIDGET-002](https://www.modifee.com/docs/errors/MDF-WIDGET-002) — "Transcription failed." - [MDF-WIDGET-004](https://www.modifee.com/docs/errors/MDF-WIDGET-004) — "Allow the microphone in your browser to dictate." - [MDF-WIDGET-005](https://www.modifee.com/docs/errors/MDF-WIDGET-005) — "The connection was lost." The widget says "We can't reach the team right now. Try again in a few minutes." - [MDF-VERCEL-001](https://www.modifee.com/docs/errors/MDF-VERCEL-001) — "Vercel could not complete that request." - [MDF-VERCEL-003](https://www.modifee.com/docs/errors/MDF-VERCEL-003) — "The preview could not be opened." - [MDF-INTERNAL-001](https://www.modifee.com/docs/errors/MDF-INTERNAL-001) — "Something broke on our end. We've been notified." ## Other errors - [MDF-AUTH-003](https://www.modifee.com/docs/errors/MDF-AUTH-003) — "You don't have access to this." This account cannot do that on the workspace or project. - [MDF-REQ-001](https://www.modifee.com/docs/errors/MDF-REQ-001) — "Something was off with that request." A required field was missing or had the wrong shape. - [MDF-REQ-002](https://www.modifee.com/docs/errors/MDF-REQ-002) — "We couldn't find that." That project, request, or widget key does not exist. - [MDF-INTERNAL-002](https://www.modifee.com/docs/errors/MDF-INTERNAL-002) — "Modifee is briefly unavailable." The service is temporarily unavailable. # Widget not showing The change button never appears on the client site. ## Symptom The site loads, and **Request a change** (**Demander un changement** / **Solicitar un cambio**) is not on the page. ## Causes ### The access marker is missing or was changed On a site without login, the script hides the button until the page URL contains the marker. The default marker is `modifee`, so the link looks like `https://client.example/?modifee`. **Confirm.** Open the site with no extra query string. The button is absent. Open the link from **Settings → Client access**. The button appears. The browser console does not warn about a missing script. After you change the marker, the old link no longer unlocks a new tab. The save confirm says "The old link will stop working. Send the new link to your client." **Fix.** Send the current link. The marker is the query key, 3 to 64 letters, digits, `_`, or `-`. It cannot be `page`, `id`, `q`, `s`, `ref`, `fbclid`, `gclid`, or a name that starts with `utm_`. See [Access marker](https://www.modifee.com/docs/client-access/access-marker). A site with login skips this gate when `data-token` is set. If that attribute is empty, the console says "Modifee: data-project and data-token are required". See [Token errors](https://www.modifee.com/docs/troubleshooting/token-errors). ### The script did not load **Confirm.** In the browser network panel, the request for `widget.js` is missing, failed, or blocked. The console may say "Modifee: missing script element" or "Modifee: data-project is required". **Settings → Widget install** stays yellow: "Widget not found on the site". **Check installation** then reports one of these: - "The widget on this page belongs to another project." - "We couldn't find the widget on" the site URL. "Paste the snippet just before `` and check again." - "We couldn't reach" the site URL, then "Connection failed", "Timed out", or "HTTP" and a status. "The widget will be marked installed as soon as it loads on the site." - "This page is rendered in the browser, so the widget script is not in the HTML we fetched from" the site URL. **Fix.** Paste the snippet for this project and deploy. The `src` must be the Modifee `widget.js`, and `data-project` must be this project's public key. A browser-rendered page can still be fine: open the live site so the script can ping. The install mark turns green once that ping arrives, or once the HTML check finds this project's key. Install guides: [Next.js App Router](https://www.modifee.com/docs/install/nextjs-app-router), [Next.js Pages Router](https://www.modifee.com/docs/install/nextjs-pages-router), [HTML](https://www.modifee.com/docs/install/html), [Other frameworks](https://www.modifee.com/docs/install/other-frameworks). ### The tab forgot the marker The script stores the unlock in `sessionStorage` under a key that starts with `modifee:access:` and ends with the project public key. The value is `1`. That lasts for the tab only. **Confirm.** The button was visible, then a new tab or a cleared site storage hides it. The same tab still shows it. Ctrl+Shift+M shows it again and writes that storage key. **Fix.** Open the marker link again, or press Ctrl+Shift+M. Do not rely on `sessionStorage` as the way clients get in. Send the link. ### Widget install looks fine, but the button is hidden A green **Widget install** mark means the script loaded or the HTML contained this project's key. It does not mean the button is visible. The marker can still be hiding it. **Confirm.** The section mark is green, or the check says the snippet matches, and the button is still absent without the marker link. **Fix.** Use the marker link from [Access marker](https://www.modifee.com/docs/client-access/access-marker). If the check says the widget belongs to another project, replace the snippet with this project's key. ### The site URL is not HTTPS **Confirm.** **Settings → Connection** is yellow: "Site URL must be a valid https address". **Check installation** cannot use an address that is not `http` or `https`, or a localhost, `.local`, or private-network host. Those come back as "We couldn't reach" the URL. **Fix.** Save a public `https` URL, deploy the site there, and press **Check installation** again. ### An ad blocker stopped the script **Confirm.** The network panel shows `widget.js` blocked by the client. Disabling the blocker makes the button appear. No Modifee error is returned. **Fix.** Ask the client to allow `widget.js` from the script origin on that site. The usual origin is `https://www.modifee.com`. ### The site's Content Security Policy blocks the script `widget.js` does four things that a strict policy can reject. Use the origin of the script `src`. The default install uses `https://www.modifee.com`. - It loads as a classic script. Allow that origin in `script-src`. - It calls `fetch` on `/api/widget/unlock`, `/api/widget/ping`, and `/api/widget/public-config` on that same origin. Allow it in `connect-src`. - It creates an iframe at `/widget/` plus the public key, with `allow="microphone"`. Allow that origin in `frame-src`. - It injects a `