Developer & Embed Docs
Embed a widget, or POST your own form into the Domain Directory database.
Available Form Types
offerpreview ↗Acquire the domain — collects bid price, phone, contact preference
partnerpreview ↗Partnership inquiry → saves lead, then iPartner login (check submission with their email)
staffingpreview ↗Join the team — collects team role, resume URL, developer flag
inquirepreview ↗General inquiry — collects phone & contact preference
leasepreview ↗Lease the domain — name, email, and a 6 / 12 / 24 month term. Only names with no Next.js template and no custom worker.
newsletterpreview ↗Community invite → Contrib firststep signup (email + role prefilled)
Option 1 — Direct URL (simplest)
Link directly to a hosted form page. No setup required. Works as a full page or in an iframe.
Examples:
- /forms/offer/agentbank.com
- /forms/partner/agentbank.com
- /forms/staffing/agentbank.com
- /forms/inquire/agentbank.com
- /forms/newsletter/agentbank.com
- /forms/lease/appmd.com
Add a button link in any HTML page:
<a href="https://www.domaindirectory.com/forms/offer/agentbank.com"
target="_blank">
Make an Offer
</a>Option 2 — iframe Embed
Drop an iframe anywhere on your page. The form handles submission internally.
<iframe
src="https://www.domaindirectory.com/forms/offer/agentbank.com"
width="100%"
height="700"
style="border:none; border-radius:16px;"
title="Make an offer for agentbank.com"
></iframe>Tip: set height to 700–900px depending on form type. The partner and staffing forms are taller.
Option 3 — JS Widget (auto-render)
Load our script and place <div data-dd-form> elements anywhere on your page. The script bootstraps the form inside each matching element. Zero framework dependencies.
Step 1 — Load the script (once per page):
<script src="https://www.domaindirectory.com/widget/dd-forms.js" defer></script>Step 2 — Place a container div:
<div
data-dd-form="offer"
data-dd-domain="agentbank.com"
></div>All attributes:
| Attribute | Required | Values |
|---|---|---|
| data-dd-form | Yes | offer | partner | staffing | inquire | lease |
| data-dd-domain | Yes | e.g. agentbank.com |
Option 4 — Next.js / React Component
If you're in a Next.js or React app, copy src/components/ServiceContactForm.tsx from the domaindirectory-nextjs repo and import it directly.
import { ServiceContactForm } from "@/components/ServiceContactForm";
// In your page / component:
<ServiceContactForm
formType="offer"
domain="agentbank.com"
displayName="AgentBank.com"
/>The component posts to https://www.domaindirectory.com/api/domain-contact/ by default. Any lander origin can call that URL from the browser.
Option 5 — Cloudflare Worker Injection
Inject dd-forms.js into any HTML response from a Cloudflare Worker (parked / lander pages). Example below uses partner — after submit, the visitor is sent to iPartner with email prefilled.
// worker.js — partner embed
export default {
async fetch(request) {
const response = await fetch(request);
const url = new URL(request.url);
const host = url.hostname.replace(/^www\./, "");
const html = await response.text();
const snippet = `
<div data-dd-form="partner" data-dd-domain="${host}"></div>
<script src="https://www.domaindirectory.com/widget/dd-forms.js" defer><\/script>
`;
// Inject before </body>
const modified = html.replace("</body>", snippet + "</body>");
return new Response(modified, {
headers: { "Content-Type": "text/html" },
});
},
};Partner success tells visitors to check their submission on ipartner.com by logging in with their email, then opens ipartner.com/login?domain=…&email=…. Swap data-dd-form for offer, staffing, or inquire, or lease as needed.
Custom forms — post to the database
Build the form yourself. On submit, POST JSON from the visitor's browser (or from your own server). A 201 means the lead is saved. This API does not redirect — after success, send the visitor wherever you want (iPartner, Contrib, or your own thank-you page).
Offer, partner, staffing, or inquiry
<form id="dd-custom">
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<input name="bid_price" type="number" placeholder="Offer amount" />
<textarea name="message" placeholder="Message"></textarea>
<!-- honeypot: leave hidden and empty -->
<input name="website" tabindex="-1" autocomplete="off" aria-hidden="true"
style="position:absolute;left:-9999px" />
<button type="submit">Submit offer</button>
</form>
<script>
document.getElementById("dd-custom").addEventListener("submit", async (e) => {
e.preventDefault();
const fd = new FormData(e.currentTarget);
const res = await fetch("https://www.domaindirectory.com/api/domain-contact/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
domain: location.hostname.replace(/^www\./, ""),
type: "offer", // offer | partner | staffing | inquire
name: fd.get("name"),
email: fd.get("email"),
bid_price: fd.get("bid_price") || undefined,
message: fd.get("message"),
website: fd.get("website") || "",
}),
});
const data = await res.json();
if (!res.ok) {
alert(data.error || "Could not save");
return;
}
e.currentTarget.innerHTML = "<p>Saved. Thanks — we have your submission.</p>";
});
</script>- Keep the trailing slash on
/api/domain-contact/. A URL without it redirects, and browsers drop that redirect on the CORS preflight. - Call it from the page on the lander. Any
Originis allowed. A server-side POST of the same JSON also saves the row. domainandemailare required.typeisoffer,partner,staffing, orinquire.- Leave
websiteempty. If it has a value, the API pretends success and does not save. - Optional
formStartedAtis a millisecond timestamp from when the form was shown. If you send it, submit must be at least 2.5 seconds later. Omit it if you do not want that timer. - Do not send a Turnstile token from a parked domain. That check runs only on domaindirectory.com.
Newsletter
await fetch("https://www.domaindirectory.com/api/leads/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
domain_name: "appmd.com",
email: "[email protected]",
name: "Jane Smith",
source: "newsletter",
website: "",
}),
});
// { success: true } — then send them to Contrib if you want:
// https://www.contrib.com/signup/firststep?domain=appmd.com&[email protected]&ref=dd-newsletterAPI Reference
Offer, partner, staffing, and inquiry forms POST to https://www.domaindirectory.com/api/domain-contact/. Newsletter posts to https://www.domaindirectory.com/api/leads/. The browser call must include the trailing slash.
| Field | Type | Required | Notes |
|---|---|---|---|
| domain | string | Yes | e.g. agentbank.com |
| string | Yes | Valid email address | |
| type | string | No | offer | partner | staffing | inquire | contact |
| name | string | No | Submitter's name |
| phone | string | No | Phone with country code |
| company | string | No | Company name |
| message | string | No | Free-text message |
| bid_price | number | No | Offer amount in dollars |
| website | string | No | Honeypot. Must be empty or the row is not saved |
| formStartedAt | number | No | Ms timestamp. If set, submit must be ≥ 2.5s later |
Example raw POST:
const res = await fetch("https://www.domaindirectory.com/api/domain-contact/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
domain: "agentbank.com",
type: "offer",
name: "Jane Smith",
email: "[email protected]",
bid_price: 50000,
message: "I'm interested in acquiring this domain for a fintech startup.",
}),
});
const data = await res.json();
// { success: true, message: "Thank you! Your message has been received." }Origin so parked landers can post. Use the trailing-slash URL /api/domain-contact/ so the preflight is not redirected.Newsletter → Contrib Signup
Every newsletter path saves a lead (tagged dd:newsletter), then sends the visitor to Contrib registration:
- JS widget — compact name/email on any site → firststep
- React —
NewsletterForm→ firststep - Hosted page / iframe — /forms/newsletter/[domain] (role pick + what you get) → firststep with
ref=dd-newsletter-community - Cloudflare Worker — inject the JS widget on parked pages → firststep
Live demo (JS / React widget):
Option A — Direct URL / iframe (full community page):
<!-- Full page -->
<a href="https://www.domaindirectory.com/forms/newsletter/agentbank.com"
target="_blank">Join the community</a>
<!-- Or iframe -->
<iframe
src="https://www.domaindirectory.com/forms/newsletter/agentbank.com"
width="100%"
height="900"
style="border:none; border-radius:16px;"
title="Join agentbank.com on Contrib"
></iframe>Option B — JS widget (compact embed):
<script src="https://www.domaindirectory.com/widget/dd-newsletter.js" defer></script>
<div
data-dd-newsletter
data-dd-domain="agentbank.com"
data-dd-role="social"
></div>Widget attributes (all optional):
| Attribute | Default | Notes |
|---|---|---|
| data-dd-domain | current hostname | Domain passed to Contrib firststep |
| data-dd-role | (none) | Optional: marketer | social | developer | designer | writer | founder |
| data-dd-title | "Join the community" | Heading text |
| data-dd-subtitle | "Marketers, social leads…" | Subheading text |
| data-dd-button | "Join on Contrib" | Submit button label |
Option C — Next.js / React:
import { NewsletterForm } from "@/components/NewsletterForm";
<NewsletterForm
domain="agentbank.com"
role="developer"
title="Help build AgentBank"
subtitle="Contribute your skills. Earn as the brand grows."
buttonLabel="Join on Contrib"
/>Posts to https://www.domaindirectory.com/api/leads/ by default, then redirects to Contrib firststep. Override with apiEndpoint="/api/leads" for same-origin.
Option D — Cloudflare Worker injection:
// worker.js
export default {
async fetch(request) {
const response = await fetch(request);
const url = new URL(request.url);
const host = url.hostname.replace(/^www\./, "");
const html = await response.text();
const snippet = `
<div data-dd-newsletter data-dd-domain="${host}"></div>
<script src="https://www.domaindirectory.com/widget/dd-newsletter.js" defer><\/script>
`;
const modified = html.replace("</body>", snippet + "</body>");
return new Response(modified, {
headers: { "Content-Type": "text/html" },
});
},
};After submit: lead saved, then browser goes to Contrib firststep with that domain + email.
Customizing the look:
[data-dd-newsletter] {
--ddn-accent: #2563eb;
--ddn-accent-hover: #1d4ed8;
--ddn-radius: 8px;
--ddn-bg: #ffffff;
--ddn-border: #e5e7eb;
--ddn-text: #111827;
--ddn-muted: #6b7280;
--ddn-font: inherit;
--ddn-shadow: none;
}Stable classes: .ddn-card, .ddn-input, .ddn-btn. Or skip defaults:
<div data-dd-newsletter data-dd-unstyled data-dd-class="my-form"></div>
<script>window.DD_NEWSLETTER_NO_CSS = true;</script>
<script src="https://www.domaindirectory.com/widget/dd-newsletter.js" defer></script>React styling:
<NewsletterForm
domain="agentbank.com"
className="rounded-none border-2 border-black bg-zinc-50 p-8"
inputClassName="border-black"
buttonClassName="bg-black hover:bg-zinc-800"
/>Or POST directly, then redirect:
const email = "[email protected]";
const domain = "agentbank.com";
const role = "social";
await fetch("https://www.domaindirectory.com/api/leads/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email,
name: "Jane Smith",
domain_name: domain,
source: "newsletter",
}),
});
// Same destination as the widget / React form / hosted page:
window.location.href =
"https://www.contrib.com/signup/firststep"
+ "?domain=" + encodeURIComponent(domain)
+ "&email=" + encodeURIComponent(email)
+ "&role=" + encodeURIComponent(role)
+ "&ref=dd-newsletter";CORS is open on /api/leads. Duplicate email + domain pairs are de-duplicated automatically.
Contact Us
Building a custom form, embedding a widget, or sending visitors to iPartner or Contrib? Send us a message and we'll get back to you.
