Extension points
Custom Buttons
Add buttons to OnePageCRM contact and deal menus that open your app at the right record, using URL template variables.
Maintained by the OnePageCRM engineering team · Last updated Sep 1, 2026
Custom Buttons let you add your own links to the 3-dots menu on contact and deal views. Each button opens a URL you define, with template variables resolved from the current record — so one click lands the user in your app, on the right customer.
Use it to:
- Deep-link into your app preloaded with the right context (“Open in Acme” → your customer page for that contact).
- Trigger an external workflow next to the record it relates to (create an invoice, start a call, open a booking form).
- Bridge to internal tools that key off an email, phone number, or External ID.
Custom Buttons is currently in beta. Contact OnePageCRM support for enablement if the Custom buttons tab is not visible under Settings.
Set it up
Buttons are configured in the OnePageCRM web app — there’s no public API for managing them.
- Go to Settings → Custom buttons (fourth tab, beside Custom
fields), or open
app.onepagecrm.com/custom_buttonsdirectly. - Click Add, complete the fields below, and save — creating and editing happen on a single page.
- Owner or admin access is required; the tab is not shown to other users.
- Enabled buttons appear in the 3-dots menu for all account users.
Button fields
| Field | Required | Notes |
|---|---|---|
| Name | yes | The label shown in the menu. |
| URL template | yes | Must start with http://, https://, or a variable that supplies the URL (e.g. [contact.twitter]). May contain template variables. |
| Type | yes | contact or deal — which 3-dots menu the button appears in, shown as a Contact/Deal radio pair. Add two buttons to cover both. |
| Icon | no | One of default, call, mail, money, profile, tool. |
| Enabled | — | Toggle a button off without deleting it. |
If the URL field has content, changing the type asks for confirmation, then clears it.
You can create up to 25 buttons per type (25 for contacts, 25 for deals). The limit is also enforced when switching an existing button’s type — the move is rejected if the target type already has 25 buttons. The disabled buttons also count towards the limit.
Template variables
Variables use the form [entity.field]. When a user clicks the
button, each variable is replaced with the value from the current
record.
Contact variables
| Variable | Value |
|---|---|
[contact.firstname] | First name |
[contact.lastname] | Last name |
[contact.fullname] | Full name |
[contact.title] | Title (Mr, Mrs, Ms) |
[contact.jobtitle] | Job title |
[contact.email] | First email address |
[contact.phone] | First phone number |
[contact.twitter] | X (Twitter) profile URL |
[contact.id] | OnePageCRM contact ID |
[contact.address] | First address, formatted as one line |
[contact.twitter]reads the contact’s saved URL of typeonepagecrmand@onepagecrmboth resolve tohttps://x.com/onepagecrm. An already-absolute URL passes through unchanged.
Organization variables
| Variable | Value |
|---|---|
[organization.name] | Company name |
[organization.id] | OnePageCRM company ID |
Deal variables
| Variable | Value |
|---|---|
[deal.name] | Deal name |
[deal.amount] | Deal amount |
[deal.totalamount] | Total amount (amount × months) |
[deal.id] | OnePageCRM deal ID |
Custom field variables
Every custom field is available as
[contact.cf.<name>], [organization.cf.<name>], or
[deal.cf.<name>], where <name> is the field’s name lowercased with
spaces replaced by underscores. A field named Acme ID becomes:
[contact.cf.acme_id]
The Variable picker
The Variable picker sits below the URL field and inserts the placeholder at the cursor position, or replaces the selected text. Variables are grouped by button type: Contact buttons show Contact and Organization; Deal buttons show Deal, Contact and Organization. Account custom fields appear inside their group; section dividers are not offered.
Encoding
Values are percent-encoded, with one exception: a variable at the very
start of the template whose value is an absolute http(s) URL is
inserted raw, so the variable can supply the whole link.
[contact.twitter]
Text after it is kept, so you can append a path:
[contact.twitter, fallback=https://x.com]/with_replies
A leading variable that resolves to anything else is still encoded, which will produce a broken link.
Fallbacks
Provide a default with the fallback option:
[contact.cf.acme_id, fallback=unknown]
The fallback fires only when a variable resolves to no value at
all — not an empty string. In practice it works for: custom field
variables with no value, unset first/last name, title and job title fields,
[contact.twitter] when no X URL is saved, organization.* variables
when the contact has no company, an unset deal.name, and any variable
whose linked record is missing. It does not fire for
[contact.email], [contact.phone], or [contact.address] — those
resolve to an empty string when absent. IDs and deal amounts always
have a value, so a fallback on them never fires.
Example: open your app at the right customer
Say you sync customers with an External ID custom field named Acme ID. Add a contact button:
| Field | Value |
|---|---|
| Name | Open in Acme |
| Type | contact |
| URL template | https://app.acme.com/customers/[contact.cf.acme_id] |
A contact whose Acme ID is cus_8c1ab2 gets a menu item that opens:
https://app.acme.com/customers/cus_8c1ab2
No External ID yet? Key off email instead and resolve it on your side:
https://app.acme.com/lookup?email=[contact.email]&name=[contact.fullname]
Behavior notes
- Buttons open in a new browser tab (
target="_blank"withrel="noopener noreferrer"). - Contact buttons resolve
contact.*andorganization.*variables. Deal buttons resolvedeal.*plus the linked contact’scontact.*andorganization.*variables. - If a button’s template resolves to a blank URL — for example a button
pointing at
[contact.twitter]for a contact with no X/Twitter URL recorded — the button is omitted from that record’s 3-dots menu rather than rendered as a dead link. - Variables are resolved when the record view loads. Your endpoint receives a plain GET from the user’s browser — there is no signature or auth handoff. Treat incoming parameters as hints and authenticate the user in your own app as usual.
- Buttons are account-wide: every user sees enabled buttons, but only owners and admins can manage them.
See also
- External ID — give every record a stable ID in your system, then link straight to it.