Guides
The embed
Add the sign-up form to your own site with two lines of HTML.
Use your agent. Paste this into it:
Read hunchwire.com/docs/embed and add the waitlist to my site.
On this page
The embedThe embed
Add the sign-up form to any site: the founder's own site or app (own_site_forms), or hosted pages. Paste two lines into the page's HTML: the script, once per page, and an element where the form goes.
The form works only on the project's hosts. To use it on another site, add that site's domain to domains. Sign-ups from anywhere else are refused and counted in blocked_requests.
The waitlist looks as the saved form says (see Save the form), so the snippet never changes when the form does. The founder copies it from Build › Put it on your site.
GET
/projects/:id/setup/site/embed
Get the snippet.
Details
- Takes
form:waitlist(the default) orlogin. - Returns
form,snippet(paste it as is) andhosts(where it works).
curl https://app.hunchwire.com/projects/:id/setup/site/embed \
-H "Authorization: Bearer $HUNCHWIRE_TOKEN"
import os, requests
r = requests.get(
"https://app.hunchwire.com/projects/:id/setup/site/embed",
headers={"Authorization": f"Bearer {os.environ['HUNCHWIRE_TOKEN']}"},
)
r.json()
const res = await fetch("https://app.hunchwire.com/projects/:id/setup/site/embed", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.HUNCHWIRE_TOKEN}`,
},
})
const data = await res.json()
GET /projects/:id/setup/site/embed?form=login
-
The script tag holds
data-project(the project'sembed_key) and the consent details. Don't edit it.GET /projects/:id/setupalso returns the default snippet, asembed_snippet.
Save the form
Save how the waitlist form looks once, and every page with the script shows it: hosted pages, and sites that pasted the snippet. Nothing needs pasting again. Build › Form edits the same settings.
GET
/projects/:id/form
Get the saved form.
Details
contact:email, orphonefor a mobile number.theme:dark, orlightfor light pages.button: the button's label. The default is "Sign up now".message: the line under the confirmation, ornull.
curl https://app.hunchwire.com/projects/:id/form \
-H "Authorization: Bearer $HUNCHWIRE_TOKEN"
import os, requests
r = requests.get(
"https://app.hunchwire.com/projects/:id/form",
headers={"Authorization": f"Bearer {os.environ['HUNCHWIRE_TOKEN']}"},
)
r.json()
const res = await fetch("https://app.hunchwire.com/projects/:id/form", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.HUNCHWIRE_TOKEN}`,
},
})
const data = await res.json()
{"contact": "email", "theme": "dark", "button": "Sign up now", "message": null}
PATCH
/projects/:id/form
Change the saved form.
Details
- Send only what changes. An empty value goes back to the default.
buttonis at most 40 characters, andmessageat most 140. Anything else is a 422 witherrors.- Pages show a change within a minute.
curl -X PATCH https://app.hunchwire.com/projects/:id/form \
-H "Authorization: Bearer $HUNCHWIRE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"form": {"button": "Join the waitlist", "message": "We'll email you when Loop opens."}}'
import os, requests
r = requests.patch(
"https://app.hunchwire.com/projects/:id/form",
headers={"Authorization": f"Bearer {os.environ['HUNCHWIRE_TOKEN']}"},
json={"form": {"button": "Join the waitlist", "message": "We'll email you when Loop opens."}},
)
r.json()
const res = await fetch("https://app.hunchwire.com/projects/:id/form", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.HUNCHWIRE_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({"form": {"button": "Join the waitlist", "message": "We'll email you when Loop opens."}}),
})
const data = await res.json()
-
A form's own
data-option (see Form options) wins over the saved setting on that form. Use one only where a page must differ, like a pricing page'sdata-button="Join".
Preview the form
Open any page with the script with ?hunchwire=preview. The form shows as visitors see it, but takes no sign-up, and the page counts nothing. A bar at the bottom of the page switches between a visitor, someone who just joined and a friend arriving. After joining, the form shows example data, such as place #148 and an example link, never a real person's.
The forms
-
<div data-hunchwire="waitlist"></div>: an email field and a Sign up now button. Nothing on the form says "waitlist", so it works for a product that doesn't exist yet. A consent line names the project'ssenderand links Hunchwire's privacy policy: "By continuing, you agree to get emails from <sender>. Unsubscribe anytime."After someone joins, the form shows the same confirmation on every page: "You're early.", then "We're in private beta, so it isn't open yet. You're on the waitlist; updates go to <their email>." Pages can't remove or reword it. They can add a line with
data-message. While the project's referrals are on (see Referrals), the person's place in line shows under it. -
<div data-hunchwire="login"></div>: a fake login. It never sends the password or the email, and never adds anyone to the waitlist. Each submit records alogin-attemptclick and shows "Unknown email or password." Withdata-next, it sends the visitor to that page instead: use it for the founder's real login page. Analytics shows how many visitors tried to log in, under Key actions. In the API, read it from theclick:login-attemptkey action'spages.
Form options
Set these on the form's element. Each one wins over the saved form (see Save the form) on that form only.
| Option | What it does |
|---|---|
data-button="Request access" |
The button label. The default is "Sign up now". For an open waitlist, use data-button="Join the waitlist". |
data-message="…" |
On the waitlist form: one plain-text line under the confirmation, such as "First invites go to agencies with 10+ clients." At most 140 characters; longer lines are cut with "…". A leading "You're on the list." is dropped, because the confirmation already says it. On the login form: the error it shows. |
data-next="/welcome" |
The page to open after submitting: a path or a full URL. On the login form, the founder's real login page, such as data-next="https://app.example.com/login". |
data-theme="light" |
A light form, for light pages. The default is dark. |
data-contact="phone" |
The waitlist asks for a mobile number instead of an email. The person types it with its country code (+1 416 555 0123); without one, the form says how to fix it. Its consent line reads "By continuing, you agree to get messages from <sender> at this number. Reply STOP to opt out." Hunchwire never texts the number: your product does. Anything else, or no attribute, is the email form. |
data-list="whatsapp" |
The list a waitlist sign-up joins. Use it to count interest in a variant apart from the main waitlist. Up to 30 lowercase letters, digits and dashes; anything else is ignored. People shows the list, and filter[list][] picks it. |
After someone joins
- Place in line. Shows under the confirmation while the project's referrals are on (see Referrals). No attribute controls it:
data-referralsdoes nothing any more. The person sees "Your place #148" when the line moves. Places 1 to 10 add "Among the first 10", and the total is never shown. When sharers get access, they see "2 more friends and you're in." instead. Then come the sharer's line, their link (the site's home page with?ref=<code>, shown withouthttps://) and a Copy link button. Nothing shows withdata-next. Someone who signs up again sees it only in the browser that first joined. - Share buttons. Under the link, one button per post in the share kit (X, LinkedIn, Reddit, Email) opens that site with the post filled in. The person's share image shows with Save image. It's 1200×630, with the share kit's headline and "I'm #148 in line for Loop" ("I'm on the list for Loop" when the line doesn't move), at
https://app.hunchwire.com/e/<embed_key>/share/<code>.png. On hosted pages, a link with someone's?ref=uses that image as its preview (og:image,twitter:image). - Friends. A visitor who arrives with someone's
?ref=sees the offer above the form: "A friend invited you to Loop." and the friend's line. It shows only while referrals are on and the friend gets something. It never says whose link it was. - Straight in. When friends get access and the project has a Let people in address, a friend's link lets them straight in. After they sign up, the form says "You're in." and sends them to that address with a token, like an opened invite. If the page doesn't move, a Continue button opens their invite link. They see no place, link or questions.
- Straight in by number. On a
data-contact="phone"form, a friend's link lets them in without a Let people in address. The form says "You're in." and "Your friend's link got you in.", and stays on the page: there's no web sign-up by number. Usedata-messageto say where to text. Your product checksaccesswhen they first text (see the API). - The first link wins. Every page keeps a
?ref=code in the browser until that visitor signs up, so a friend can land on/and join on/signup.
Use your own form with the API
- Add
<input type="hidden" name="visitor_id" data-hunchwire-visitor>to a form on a page with the script. The script fills in the visitor's id. - Add
<input type="hidden" name="ref" data-hunchwire-ref>too. The script fills in the friend's code the visitor arrived with, or leaves it empty. - Send both to
POST /v1/peoplefrom your server (see API). The sign-up then counts in Analytics with the visitor's channel, campaign and pages.
A link from one of the project's hosts to another carries the visitor across. The script adds hw_vid and ref to the link, and the page it opens drops them from the address bar. So a landing page and a join page on two hosts count as one visitor. The script tag lists the hosts as data-hosts, so paste the snippet again after adding a domain.
Made from skill.md, the file agents read. Add .md to any page's address for its Markdown.