HOAcrew

Add the form to a plain HTML site

Two lines anywhere inside the body, in the place you want the form to appear. Nothing goes in the head and there is nothing to install.

Where the code goes
anywhere inside the body
How the form arrives
Inside your page
the visitor never leaves your site
What you paste
Two lines of HTML
Addresses per key
10
list every spelling your site answers on

Paste it into the body

You need your key first.

It is on the plugin page in your console, under Settings, Website plugin. That page is also where you list the web addresses your form is allowed to appear on, and it will not work anywhere you have not listed. The overview walks through getting one.

This is the code. Replace hoac_embed_your_key_here with the key from your console. That is the only edit it needs.

The snippet

<div data-hoacrew-proposal-form data-key="hoac_embed_your_key_here"><a href="https://hoacrew.com/embed/w/hoac_embed_your_key_here">Request a proposal</a></div>
<script src="https://hoacrew.com/embed/v1.js" async></script>

Two lines: the place the form goes, and the script that puts it there. The link inside the first line is a plain one to your hosted form, and it is what a visitor gets if the script never arrives — a browser with scripting off, a corporate proxy, a blocker. The loader clears it the moment it runs, so nobody sees both. That wording is yours: change Request a proposal to whatever you would rather it said and nothing else is affected.

The <div> is where the form appears; the <script> puts it there. Both belong inside <body>, and the div has to come first in the document. Beyond that the placement is yours — the form fills the width of whatever contains it and asks for the height it needs.

For a form in two places, repeat the <div> and put the same key on both. Your company has one install key and both forms use it; the two mount independently, and each can carry different options. The <script> stays on the page once however many divs there are.

Register both spellings of your address.

To a browser, acme-lawns.com and www.acme-lawns.com are two different places. If your site answers on both, list both on the plugin page. The same goes for http:// against https://. This is the reason behind almost every form that never appears.

A complete worked example

Save this as a file, put your key in it, put it on your web server, and it works. It is a whole page rather than a fragment so there is nothing left to infer.

contact.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Contact — Acme Lawns</title>
  </head>
  <body>
    <h1>Ask us for a proposal</h1>
    <p>Tell us about your community and we will put a proposal together.</p>

    <div data-hoacrew-proposal-form data-key="hoac_embed_your_key_here"><a href="https://hoacrew.com/embed/w/hoac_embed_your_key_here">Request a proposal</a></div>
    <script src="https://hoacrew.com/embed/v1.js" async></script>
  </body>
</html>

The options all go on the same <div> as attributes. Set a heading, a service to preselect, a light or dark treatment, and a color for the send button:

With every option set

<div data-hoacrew-proposal-form data-key="hoac_embed_your_key_here" data-service="Landscaping" data-heading="Get a proposal for your community" data-theme="light" data-accent="#1f7a4d"><a href="https://hoacrew.com/embed/w/hoac_embed_your_key_here?service=Landscaping&amp;heading=Get%20a%20proposal%20for%20your%20community&amp;accent=%231f7a4d">Get a proposal for your community</a></div>
<script src="https://hoacrew.com/embed/v1.js" async></script>

Anything that is not a hex color is ignored rather than placed into the page, and the text on the button is set to whichever of near-black or white reads better on the color you chose, so an unlucky choice does not produce a button nobody can read.

Loading order, and pages built after load

The script is marked async and does nothing until the document is ready, so it never holds up your page. When it runs it looks for every element carrying data-hoacrew-proposal-form and puts a frame inside each one.

If part of your page appears later — a tab, a modal, anything drawn by your own code after the document loaded — the script has already finished looking. Call this once the new element is in the document and it picks it up:

After you add a mount point yourself

if (window.HOAcrewEmbed) window.HOAcrewEmbed.mount();

It is safe to call as often as you like: a mount point that already has a form is skipped.

What the script touches on your page.

It appends one frame inside each of your mount elements and listens for messages from those frames. It sets no cookies, reads no storage, makes no other network request, and adds nothing to the page’s global scope except window.HOAcrewEmbed. The form itself lives inside the frame, on our side of a boundary the browser enforces, so nothing on your page can read what a visitor types into it — and nothing in it can read your page.

How to tell it worked

  1. Open the page over http:// or https:// from a web server, not as a file:// path off your desktop. A page opened from disk has no web address for us to check against your list, and the form will not show.
  2. Send a test, taking more than a few seconds over it: a submission completed unusually fast is filed as suspected spam.
  3. Open Settings → Website plugin in your HOAcrew console. Your test is in the list.

Testing on your own machine works: register the address your local server answers on, such as localhost:3000, and the form appears there like anywhere else.

If your server sets a security policy

Most websites have no Content-Security-Policy and this section does not apply to them. If yours has one — a security plugin added it, your host sets it, or whoever built the site wrote one — it needs to allow two things from us:

The two allowances

script-src  https://hoacrew.com
frame-src   https://hoacrew.com

The first lets the loader script run. The second lets the form’s frame render. Allow the first and forget the second and you get a blank space where the form should be, with a line in the browser’s developer console naming frame-src. Nothing else is needed: the form loads no fonts, no analytics and no other company’s code, so there is no third allowance hiding behind these two.

On a site you run yourself the policy is wherever you put it — an nginx or Apache header, a line in your framework’s config, or a <meta> tag in the head. Whichever it is, the two source lists need our address on them.

As a meta tag, if that is where yours lives

<meta http-equiv="Content-Security-Policy"
      content="script-src 'self' https://hoacrew.com; frame-src https://hoacrew.com">

If you use nonces or hashes for scripts, our loader is an ordinary external script and needs neither — a host allowance is enough. The snippet carries no inline JavaScript and no inline style on purpose, so you never need unsafe-inline for it.

The same form, somewhere else