Widgets and editor
Every Moat page type can be embedded with a script tag. All widgets are plain JavaScript with no framework, and several can share one page.
https://moat.page/profile/widget.js. There is no /widget.js at the site root.Profile card#
<script src="https://moat.page/profile/widget.js" defer></script>
<div class="moat-widget"
data-public-key="PUBLIC_KEY"
data-level="public"
data-theme="light"
data-refresh="true"></div>| Attribute | Values | Default |
|---|---|---|
data-public-key | The person's public key | Required |
data-level | strip, public, full | public |
data-theme | light, dark | light |
data-refresh | true, false | Shown |
Levels
| Level | Fields |
|---|---|
strip | Photo, name, title, company, location, timezone, pronouns, follower and following counts |
public | Strip plus headline, about, open-to-work status, skills, status signals, social links, website |
full | Public plus experience, education, certifications, projects, languages, honors, volunteering, publications, featured links |
Email and phone are only returned to server requests made with a partner key or the person's private key. They never reach a browser through the widget.
JavaScript API
// Render into any element
MoatProfile.render({
public_key: "PUBLIC_KEY",
target: "#profile-card",
level: "public",
theme: "light",
});
// Or fetch the data and render it yourself
const data = await MoatProfile.get({ public_key: "PUBLIC_KEY", level: "public" });
console.log(data.output.user.full_name);
// Point the widget at your own proxy (optional)
MoatProfile.configure({ apiUrl: "https://yourapp.example/proxy/moat-widget" });Page-level settings
Set these before widget.js loads.
| Variable | Default | Purpose |
|---|---|---|
window.MoatViewerKey | empty | Viewer's public key. Enables the follow button |
window.MOAT_SHOW_REFRESH | true | Show the refresh icon on every card |
window.MOAT_DB_TTL | 21600 | Browser cache lifetime in seconds (six hours) |
window.MOAT_API_BASE | Moat's endpoint | Override when proxying through your server |
Profile, company and service views#
Full-page views for each type, with their own stylesheet and a data-level of strip, public or full. Pin the version query string and bump it when you upgrade, because these files are cached for a long time.
<link rel="stylesheet" href="https://moat.page/cdn/widgets/moat-profile-view/moat-profile-view.css?v=20260715"> <div class="moat-profile-view" data-item-key="PROFILE_ITEM_KEY" data-public-key="VIEWER_PUBLIC_KEY"></div> <script src="https://moat.page/cdn/widgets/moat-profile-view/moat-profile-view.js?v=20260715"></script>
<link rel="stylesheet" href="https://moat.page/cdn/widgets/moat-company-view/moat-company-view.css?v=20260716"> <div class="moat-company-view" data-item-key="co_COMPANY_KEY" data-level="public"></div> <script src="https://moat.page/cdn/widgets/moat-company-view/moat-company-view.js?v=20260716"></script>
<link rel="stylesheet" href="https://moat.page/cdn/widgets/moat-service-view/moat-service-view.css?v=20260716"> <div class="moat-service-view" data-item-key="sv_SERVICE_KEY" data-level="public"></div> <script src="https://moat.page/cdn/widgets/moat-service-view/moat-service-view.js?v=20260716"></script>
Optional attributes: data-back-url and data-back-label add a back link, and data-edit-url shows an Edit button to the owner. The Edit button is cosmetic. Your edit URL must check authorization itself.
The profile view's Message button fires a moat:message event with the person's public_key and name, so your app can open its own composer.
Theming
Views read CSS custom properties on their root element or any ancestor.
.moat-profile-view {
--mpv-accent: #007AFF;
--mpv-text: #141413;
--mpv-bg: #FFFFFF;
--mpv-radius: 16px;
--mpv-font: "Inter", system-ui, sans-serif;
}Directory lists#
One bundle renders people, company and service directories, plus company and service create forms.
<link rel="stylesheet" href="https://moat.page/cdn/widgets/moat-directory/moat-directory.css?v=VERSION"> <div class="moat-widget" data-widget="profile-list"></div> <script src="https://moat.page/cdn/widgets/moat-directory/moat-directory.js?v=VERSION" async></script>
data-widget accepts profile-list, company-list, service-list, company-form and service-form. Set data-link-base to keep navigation on your site.
In-place editor#
Let people edit their Moat page without leaving your app. Saves go straight to Moat, authorized by a short-lived signature your server creates.
<link rel="stylesheet" href="https://moat.page/cdn/widgets/moat-editor/moat-editor.css?v=VERSION">
<div class="moat-editor"
data-app="profile"
data-public-key="PUBLIC_KEY"
data-auth-email="EMAIL"
data-auth-ts="UNIX_TIMESTAMP"
data-auth-sig="SIGNATURE"
data-allowed-sections="basic,experience,about"></div>
<script src="https://moat.page/cdn/widgets/moat-editor/moat-editor.js?v=VERSION" async></script>// On your server. Never expose the API key.
$ts = time();
$sig = hash_hmac('sha256', $email . '|' . $ts . '|' . $public_key, MOAT_XSITE_API_KEY);
// Signatures expire after 4 hours.Limit what can be edited with data-allowed-sections, or show only the fields of one level with data-level.
Allowed domains#
Cross-site requests are accepted only from domains on your app's allowlist, including subdomain wildcards and localhost for development. If a new domain shows a network error, ask us to add it.