Brand

Show your product's name, logo and colour on the pages and emails NoClick sends your users.

When NoClick asks one of your users something for you, the page they answer on and the email that brings them there carry your brand, not NoClick's.

import noclick

noclick.Brand.set(
    name="Acme",
    logo_url="https://acme.com/logo.png",
    color="#FF5500",
    support_url="https://acme.com/help",
    email_from_name="Acme Support",
)
  • name and logo_url head the page.
  • color (as "#RRGGBB", or the short "#RGB"; it's kept as lowercase #rrggbb) is the page's accent.
  • support_url is linked from the page, for people who have a question.
  • email_from_name is the sender name on the emails.

An account has one brand. set replaces it: a field you leave out is cleared. To change one field and keep the rest, use update, where None clears a field:

noclick.Brand.update(color="#1A73E8")    # the name, logo and the rest stay
noclick.Brand.update(support_url=None)   # no support link from now on

Before you've set a brand, update changes NoClick's default one: the name stays NoClick until you give it yours.

brand = noclick.Brand.get()
print(brand.name, brand.is_default)

noclick.Brand.reset()   # back to NoClick's defaults

is_default is True while you haven't set a brand.

Serve the pages from your own domain

By default the pages live on NoClick's host. With domain, the approval, question and hand-off pages your users see are served from a host of yours, and the emails that bring them there link to it and name only your brand:

noclick.Brand.update(domain="connect.acme.com")

domain is a domain your account holds, or a subdomain of one, that serves nothing else. It takes one CNAME record: a bought domain gets it at once, and a connected one lists it in its records until it's added. The domain's serves then includes brand. Requests made once the record is live and the host's certificate is issued link to it; links already sent keep working, and their pages open on your host too. The emails still come from NoClick's address, under your email_from_name, and connect links stay on NoClick's host for now. domain=None moves the pages back to NoClick's host, and the host stops serving them.

Use your own OAuth apps

When a user connects Google, Slack or another service, the consent screen names the OAuth app asking for access: NoClick's, unless you bring your own. Create the app at the provider with the redirect URI your brand lists for it, keep its client id and secret in an account secret under CLIENT_ID and CLIENT_SECRET, and name it per provider:

print(noclick.Brand.get().oauth_redirect_urls["google"])   # register this as the app's redirect URI

google_app = noclick.Secret.from_name("google-oauth-app", create_if_missing=True, values={
    "CLIENT_ID": "1234-abc.apps.googleusercontent.com",
    "CLIENT_SECRET": "...",
})
noclick.Brand.update(oauth_apps={"google": google_app})

The consent screen then shows your app's name and logo, which some scopes need anyway: a provider may ask that restricted scopes, such as reading all of a user's mail, come from an app that has passed its own review.

You can bring an app for Asana, Box, ClickUp, GitLab, Google (Gmail, Calendar, Drive and the rest of Google's services), Intercom, Klaviyo, monday.com, PagerDuty, Pipedrive, Slack, Webflow and Zoom; oauth_redirect_urls has the redirect URI for each. Naming any other provider raises noclick.InvalidRequest, and so does a secret that isn't your account's or lacks either key.

Connect links made after you name an app sign in with it, and each connection keeps the app it was made with: its access refreshes on that app too, so naming another app later, or deleting the secret, changes only the links made after. Connections made before keep NoClick's app until they're reconnected. A link made with an app whose secret has since been deleted, or lost a key, can't connect that provider; make a new link.

update changes only the providers you name: map one to None and links made after sign in with NoClick's app again, or pass oauth_apps=None to remove them all. set replaces the whole brand, oauth_apps included.

noclick.Brand.update(oauth_apps={"slack": noclick.Secret.from_name("slack-oauth-app")})   # Google's stays
noclick.Brand.update(oauth_apps={"google": None})   # new Google links use NoClick's app