# Team members
How to add and manage team members in your Loops account.
It is free to add additional team members to your account.
Here's how to add team members to your team:
1. Visit [https://app.loops.so/settings?page=team](https://app.loops.so/settings?page=team)
2. You'll be able to manage invites and members of your team.
3. When you remove someone from your team, they will be established with a new Loops team of their own.
That's it! 🎉
# Change your login email
How to update the email address you use to log in to Loops.
You will need the account owner role to change your email address.
1. Ensure you have access to your new email address.
2. Visit [https://app.loops.so/settings?page=team](https://app.loops.so/settings?page=team)
3. Invite your new email address to your team.
4. Accept the invite from an incognito window or a different browser.
5. Once the new email address has joined the team, promote it to an owner role.
6. Remove your old email address from the team.
# Free plan
Learn about our free plan.
**The Loops Free Plan is available to everyone who stores under 1,000 contacts in Loops.**
You can also send up to 2,000 emails every 30 days (marketing and transactional emails are both counted in this total).
After you've exceeded the 1,000 contact limit, you'll be prompted to upgrade to a paid plan. You can upgrade to a paid plan at any time by clicking **Start subscription** at the top of your [Billing page](https://app.loops.so/settings?page=billing).
On the free plan, light branding will be placed at the bottom of your emails.
### Key Benefits of the Free Plan
* **Start free**: Store up to 1,000 contacts and send up to 2,000 emails every 30 days.
* **Full functionality**: Access all features, including marketing and transactional emails, without restrictions.
* **Easy upgrade**: Seamlessly transition to a paid plan when your contact list grows.
For more information or any questions, please contact [chris@loops.so](mailto:chris@loops.so).
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/free-plan.png)
# Notifications
Learn how to receive notifications about new Loops contacts in external tools.
You will receive a notification when a contact is added to your audience through the API, integrations or form submission. You will not receive notifications for manually added users via CSV or other methods.
You can manage your notifications in the [Notifications](https://app.loops.so/settings?page=notifications) page.
## Email notifications
By default, you will receive an email notification from Loopsbot when a contact is added to your audience. You can disable this notification by toggling the **Notifications enabled** switch in the [Notifications section](https://app.loops.so/settings?page=notifications) of your Settings. If you'd like to receive email notifications again, you can toggle the switch back on. This setting is individual to your user account, and won't propagate to the rest of your team.
## Slack notifications
You can receive notifications in Slack for new contacts. Please note, this is a global setting and will apply to all additional seats in your account.
### Set up Slack notifications
1. Go to [Settings -> Notifications](https://app.loops.so/settings?page=notifications).
2. Click the link to be redirected to Slack for authorization.
3. Select the channel you want to add the bot to.
The bot must be invited to private channels before they become visible in the dropdown.
4. Send a test message to verify the integration works.
That's it! All new contacts added to your audience will now send a notification to the selected Slack channel.
### Other options
Here are a few other ways to get Slack notifications for new contacts:
1. Install an email add-on to send individual emails from [Gmail](https://slack.com/apps/AEFLFJR9Q-slack-for-gmail) or [Outlook](https://slack.com/apps/AFS3736H3-slack-for-outlook) to channels or DMs (free).
2. Create a forwarding address to send individual emails to your DM with Slackbot (free).
[View the full documentation from Slack](https://slack.com/help/articles/206819278-Send-emails-to-Slack) for more information.
# CSV Upload
Easily add contacts to Loops by uploading a CSV file.
## Add new contacts via CSV
1. Select **Import** in the top right of the [Audience](https://app.loops.so/audience) page.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/select-import-users.png)
2. Hover on **CSV** and click **Upload CSV**. Download the [example formatted CSV](https://app.loops.so/loops_sample.csv) to get an idea of the columns we use. By default, we recommend using at least `Email`, `First Name`, `Last Name`, `User Group` and `Source` columns.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/import-users.png)
3. After uploading the CSV you'll have a chance to review any duplicates or missing information before finishing.
4. When the upload is finished, all the uploaded contacts can be viewed in the Audience page. That's it! 🎊
## Update contacts via CSV
You can also upload a CSV file to update your existing contacts in bulk.
You can either download a CSV from your Audience page in Loops, edit the data and re-upload it, or start with a new CSV file and just include the contacts and columns you want to update.
When updating contacts, Loops will first look for a matching contact using the value in the `User ID` column, then the `Email` column.
If a contact is found, Loops will update the contact using the data provided in the CSV file. If a contact is not found with either `User ID` or `Email` values, a new contact will be created using the data provided.
Note: If a contact is found using `User ID` and its email address does not match the provided `Email` value, the contact will not be updated and an error will be recorded.
## View previous CSV uploads
After uploading CSV files you can view a history of your uploads plus details for each file's rows.
On the [Audience page](https://app.loops.so/audience) click **Import contacts**, hover on **CSV** and click **Upload CSV**. On the next page click on **View imports**, which will show you a list of all of your past uploads.
Clicking on one of your uploads will let you view lists of all new, updated or duplicated contacts plus a list of any errors from the import.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/csv-history.png)
## Important notes
* All contacts uploaded will be automatically marked as subscribed. If you want to mark imported contacts as unsubscribed add a "Subscribed" column into your CSV file and use `false` as the column value.
* The importer does not re-subscribe contacts who are marked as unsubscribed in your Audience.
* The default `Source` value for each uploaded contact will be "CSV Upload". You can change this by adding a `Source` column to your CSV file and specifying a custom value.
* Cells that are empty in the CSV file will not overwrite existing data in Loops. If you want to clear a field, you will need to provide a value of `null` in the CSV file (4 characters, all lowercase).
# Integrations
Connect Loops to external platforms to automatically add contacts to your audience.
We have a range of integrations with other platforms, which allow syncing of data between services you use.
For example, you can add users from thousands of apps through [Segment](/integrations/segment) or [Zapier](/integrations/zapier), or use forms on platforms like [Framer](/integrations/framer) or [Webflow](/integrations/webflow) to let contacts sign up to your mailing list.
[Go to the Integrations page](/integrations) to view the full list.
# API
Loops provides a REST API to manage your contacts.
With [the Loops API](/api-reference), you can easily manage contacts directly from your application or service.
For example, creating a new contact is as easy as sending a `POST` request to `https://app.loops.so/api/v1/contacts/create`.
```json
{
"email": "adam@loops.so",
"firstName": "Adam",
"lastName": "Kaczmarek",
"favoriteColor": "blue",
"userGroup": "Founders",
"source": "Signup form Service"
}
```
We also offer endpoints for finding, updating and deleting contacts (plus some other features like sending transactional email and sending events).
[Go to our API reference](/api-reference) for a full guide.
# API key
GET /v1/api-key
Test that an API key is valid.
## Request
No parameters.
## Response
### Success
The name of the team the API key belongs to.
### Error
An error message.
```json Response
{
"success": true,
"teamName": "My team"
}
```
```json 401 response
{
"error": "Invalid API key"
}
```
# API Changelog
Stay up-to-date with changes to our API.
Improvement: the maximum payload size for the transactional endpoint has been increased from 1MB to 4MB, allowing for more or larger attachments.
New: our new [Nuxt module](/sdks/nuxt) is now out!
New: our new [Ruby SDK](/sdks/ruby) is available!
New: we added an `isPublic` attribute to mailing list objects in the [List mailing lists](/api-reference/list-mailing-lists) endpoint.
New: there's a new `addToAudience` parameter in the [Send transactional email](/api-reference/send-transactional-email) endpoint can add contacts to your audience.
New: support for our new [mailing lists](/contacts/mailing-lists) feature.
You can now add contacts to and remove contacts from mailing lists in the [Create contact](/api-reference/create-contact), [Update contact](/api-reference/update-contact) and [Send event](/api-reference/send-event) endpoints.
There is also a [new endpoint](/api-reference/list-mailing-lists) for retrieving your mailing lists.
New: you can now [Find contacts](/api-reference/find-contact) by `userId`.
New: a new endpoint for testing your integration and/or API key: [API key](/api-reference/api-key).
New: you can now include [event properties](/events/properties) in requests to the [Send event](/api-reference/send-event) endpoint.
Improvement: we removed behavior that returned a `400 Bad Request` response if an unrecognized property was added to Contact endpoints.
Improvement: sending in a payload that contains an unrecognized property will now return a `400 Bad Request` response.
Clarification in the API docs that `userId` can be used in a [Send event](/api-reference/send-event) request.
New: we added a new endpoint for [querying custom contact properties](/api-reference/list-custom-fields).
Our [official JavaScript/TypeScript SDK](/sdks/javascript) is now available!
New: we now accept dates as a custom [contact property](/contacts/properties) type. [View the available formats](/contacts/properties#dates).
# Create contact
POST /v1/contacts/create
Create a new contact with an email address and any other contact properties.
## Request
### Body
The contact's email address.
The contact's first name.
The contact's last name.
A custom source value to replace the default "API". [Read
more](/contacts/properties#source)
Whether the contact will receive campaign and loops emails. [Read more](/contacts/properties#subscribed)
You can use groups to segment users when sending emails. Currently, a contact
can only be in one user group. [Read more](/contacts/properties#user-group)
A unique user ID (for example, from an external application). [Read
more](/contacts/properties#user-id)
Key-value pairs of mailing list IDs and a `boolean` denoting if the contact
should be added (`true`) or removed (`false`) from the list. [Read
more](/contacts/mailing-lists#api)
```json
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": false
}
```
### Custom properties
You can also include [custom contact properties](/contacts/properties) in your request body. These should be added as top-level attributes in the request.
Custom properties can be of type `string`, `number`, `boolean` or `date` ([see allowed date formats](/contacts/properties#dates)).
```json
{
"email": "hello@gmail.com",
"plan": "pro", /* Custom property */
"dateJoined": 1704711066 /* Custom property */
}
```
There are a few [reserved names](/contacts/properties#reserved-names) that you cannot use for custom properties.
To empty or reset the value of a contact property, send a `null` value.
## Response
### Success
The ID of the new contact.
### Error
An error message.
```json Response
{
"success": true,
"id": "id_of_contact"
}
```
```json Error response
{
"success": false,
"message": "An error message."
}
```
# Delete contact
POST /v1/contacts/delete
Delete a contact by email address or user ID.
## Request
### Body
You can delete a contact by using either their `email` or `userId` value.
The contact's email address.
The contact's `userId` value.
## Response
### Success
"Contact deleted."
### Error
An error message.
```json Response
{
"success": true,
"message": "Contact deleted."
}
```
```json Error response
{
"success": false,
"message": "An error message."
}
```
# Find contact
GET /v1/contacts/find
Find a contact by email address or user ID.
## Request
### Query parameters
Search by email or user ID. Only one parameter is allowed.
The contact's email address. Make sure it is [URI-encoded](https://en.wikipedia.org/wiki/Percent-encoding).
The contact's unique user ID.
## Response
This endpoint will return a list of contact objects containing all default properties and any [custom properties](/contacts/properties).
If no contact is found, an empty list will be returned.
The contact's Loops-assigned ID.
The contact's email address.
The contact's first name.
The contact's last name.
The source the contact was created from.
Whether the contact will receive campaign and loops emails.
The contact's user group.
The contact's unique user ID.
Mailing lists the contact is subscribed to, represented by key-value pairs of mailing list IDs and `true`.
```json Response
[
{
"id": "cll6b3i8901a9jx0oyktl2m4u",
"email": "hello@gmail.com",
"firstName": "Bob",
"lastName": null,
"source": "API",
"subscribed": true,
"userGroup": "",
"userId": null,
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true
}
}
]
```
```json No contact found response
[]
```
# API Introduction
The Loops REST API lets you manage your contacts, send events and send transactional email.
## Authentication
Your Loops API key should never be used client side or exposed to your end
users.
Start here if you want to use the Loops API to add contacts to your Loops audience,
update their attributes, and send events to Loops.
To get started, you'll need an API key. Visit the Loops settings page and click “Generate new key”
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/authentication-1.png)
This creates an API key. You can assign it a human-readable name:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/authentication-2.png)
We suggest using a different API key for different purposes. You can revoke an API key at any time with the trash icon.
When making an API call, add an Authorization header and set the API key as a Bearer token:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/authentication-3.png)
You can test your API key by making a `GET` request to [https://app.loops.so/api/v1/api-key](https://app.loops.so/api/v1/api-key). If successful, you will receive `{ "success": true }`
As a Curl request (replace `d2d561f5ff80136f69b4b5a31b9fb3c9` with your own API key):
```bash
curl https://app.loops.so/api/v1/api-key -H "Accept: application/json" -H "Authorization: Bearer d2d561f5ff80136f69b4b5a31b9fb3c9"
```
## Rate Limiting
To ensure the quality of service for all users, our API is rate limited. This means there's a limit to the number of requests your application can make to our API in a certain time frame. The baseline rate limit is **10 requests per second per team**.
To see your current usage, we provide the following response headers in every API response:
* `x-ratelimit-limit`: The maximum number of requests you can make per second.
* `x-ratelimit-remaining`: The number of requests remaining in the current rate limit window.
Here is an example of a successful response with rate limit headers:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/api-successful-response.png)
If you exceed this limit, you'll receive a response with HTTP status `429 Too Many Requests`. Here is an example of a failed response with rate limit headers:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/api-rate-limited.png)
It's important to handle these 429 responses in your application. We recommend implementing retries with an exponential backoff strategy.
If your use case requires a higher limit, please [contact us](mailto:help@loops.so) and we'll be happy to discuss your needs.
## Debugging
Sometimes things go wrong. Here are some tips to help you debug your API requests.
If you are having trouble with the API, we recommend using a tool like [Postman](https://www.postman.com/) to test your requests.
1. Handling CORS Errors:
* The Loops API does not support cross-origin requests made from client-side JavaScript. To avoid CORS errors, make sure to issue your requests from a server-side application.
2. Dealing with "Not Authenticated" Codes:
* Make sure you have generated an API key from the Loops settings page and that you are including it in your requests.
* Your API key should be included in the "Authorization" header of your request, following the format "Authorization: Bearer \{YOUR\_API\_KEY}".
3. Handling Rate Limiting (429 Response):
* The Loops API allows a maximum of 10 requests per second per team. If you receive a "429 Too Many Requests" response, this means you have exceeded this limit.
* The "x-ratelimit-limit" and "x-ratelimit-remaining" headers in the response can provide information about your current rate limit usage.
4. Authorization Header:
* Ensure that you are correctly including the "Authorization" header in your requests. The value of this header should follow the format "Bearer \{YOUR\_API\_KEY}".
5. Handling 400-level Responses:
* 400-level responses typically indicate that there was a problem with the request. The response body will contain more information about what went wrong, so be sure to check it for details.
* Check on your request type (GET, POST, PUT, DELETE) and ensure that you are using the correct one for the endpoint you are trying to access.
6. Handling Issues with Contacts API:
* Make sure to include at least the "email" field in your requests when adding or updating contacts.
* For searching contacts, replace `URI_ENCODED_EMAIL` with the URL-encoded email you are looking for in the GET request.
7. Handling Issues with Events API:
* When sending events, ensure that both the "email" and "eventName" fields are included in your requests.
If you have followed these steps and are still experiencing issues, don't hesitate to [reach out to the Loops team](https://app.loops.so/settings?page=support) for further assistance.
## OpenAPI spec
Get started quickly with the Loops API using our OpenAPI documents.
You can import these documents into an API client like Postman or Insomnia to see and use all of our endpoints, with example requests and expected responses.
* **YAML:** [app.loops.so/openapi.yaml](https://app.loops.so/openapi.yaml)
* **JSON:** [app.loops.so/openapi.json](https://app.loops.so/openapi.json)
## SDKs
SDKs are software packages built on top of the API, making it easier to integrate into your project.
The official JavaScript/TypeScript SDK for Loops.
} href="/sdks/ruby">
The official Ruby SDK for Loops.
### Unofficial SDKs
The following SDKs are community-submitted and have not been officially reviewed or endorsed by Loops. We recommend thoroughly testing and reviewing the code before integrating it into your project.
* [Laravel](https://github.com/plutolinks/laravel-loops) by PlutoLinks
* [PHP](https://github.com/plutolinks/loops-php) by PlutoLinks
* [Ruby on Rails](https://github.com/danielfriis/loops_rails) by Daniel Friis
[Submit an SDK](mailto:dan@loops.so)
## API Reference
The base URL for the API is `https://app.loops.so/api`
### Contacts
Manage contacts.
### Mailing lists
View your mailing lists.
### Events
Send events to trigger emails in loops.
### Transactional email
Send a transactional email.
### Custom fields
View your account's custom contact properties.
### API key
Test your API key.
# List custom fields
GET /v1/contacts/customFields
Retrieve a list of your account's custom contact properties.
## Request
No parameters.
## Response
This endpoint will return a list of custom field objects.
If your account has no custom fields, an empty list will be returned.
The property's name key.
The human-friendly label for this property.
The type of property (one of `string`, `number`, `boolean` or `date`).
```json Response
[
{
"key": "favoriteColor",
"label": "Favorite Color",
"type": "string"
},
{
"key": "plan",
"label": "Plan",
"type": "string"
}
]
```
```json No custom fields response
[]
```
# List mailing lists
GET /v1/lists
Retrieve a list of your account's mailing lists.
## Request
No parameters.
## Response
This endpoint will return a list of mailing list objects.
If your account has no mailing lists, an empty list will be returned.
The ID of the list.
The name of the list.
Whether the list is public (`true`) or private (`false`). [Read more](/contacts/mailing-lists#list-visibility)
```json Response
[
{
"id": "clxf1nxlb000t0ml79ajwcsj0",
"name": "Mailing List Beta",
"isPublic": true
},
{
"id": "clxf2q43u00010mlh12q9ggx1",
"name": "Product B Launch",
"isPublic": true
}
]
```
# Send event
POST https://app.loops.so/api/v1/events/send
Send events to trigger emails in Loops.
## Request
### Body
Provide either an `email` or `userId` value or both to identify the contact.
If both are provided, the system will look for a contact with either a
matching `email` or `userId` value. If a contact is found for one of the
values (e.g. `email`), the other value (e.g. `userId`) will be updated. If a
contact is not found, a new contact will be created using both `email` and
`userId` values.
The contact's email address.
The contact's unique user ID. This must already have been added to your
contact in Loops.
The name of the event.
An object containing event property data for the event. Values can be of type
`string`, `number`, `boolean` or `date`. [Read more](/events/properties)
Key-value pairs of mailing list IDs and a `boolean` denoting if the contact
should be added (`true`) or removed (`false`) from the list. [Read
more](/contacts/mailing-lists#api)
```json
{
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": false
}
}
```
### Contact properties
You can also include default and custom [contact properties](/contacts/properties) in your request body, which will update the contact in Loops. These should be added as top-level attributes in the request.
Contact properties can be of type `string`, `number`, `boolean` or `date` ([see allowed date formats](/contacts/properties#dates)).
```json
{
"email": "hello@gmail.com",
"eventName": "signup",
"firstName": "Bob", /* Contact property */
"plan": "pro" /* Custom contact property */
}
```
There are a few [reserved names](/contacts/properties#reserved-names) that you cannot use for custom properties.
To empty or reset the value of a contact property, send a `null` value.
## Response
```json Response
{
"success": true
}
```
```json Error response
{
"success": false,
"message": "An error message."
}
```
# Send transactional email
POST /v1/transactional
Send a transactional email to a contact.
## Request
### Body
The email address of the recipient.
The ID of the transactional email to send.
If `true`, a contact will be created in your audience using the `email` value (if a matching contact doesn't already exist).
An object containing data as defined by the data variables added to the transactional email template. Values can be of type `string` or `number`.
Please [email us](mailto:help@loops.so) to enable attachments on your account before using them with the API.
An object containing file(s) sent along with an email message.
The name of the file, shown in email clients.
The MIME type of the file.
The base64-encoded content of the file.
## Response
### Success
### Error
```json Response
{
"success": true
}
```
```json Error response
{
"success": false,
"path": "dataVariables",
"message": "There are required fields for this email. You need to include a 'dataVariables' object with the required fields."
}
```
```json Error response
{
"success": false,
"error": {
"path": "dataVariables",
"message": "Missing required fields: login_url"
},
"transactionalId": "clfq6dinn000yl70fgwwyp82l"
}
```
# Update contact
PUT /v1/contacts/update
Update or create a contact.
Update an existing contact by sending a request containing contact properties.
This endpoint will create a contact if a matching contact does not already exist in your audience.
If you want to update a contact's email address, the contact will first need a
`userId` value. You can then make a request containing the `userId` field
along with an updated email address.
## Request
### Body
The contact's email address. If there is no contact with this email, one will
be created.
The contact's first name.
The contact's last name.
A custom source value to replace the default "API". [Read
more](/contacts/properties#source)
Whether the contact will receive campaign and loops emails. [Read more](/contacts/properties#subscribed)
You can use groups to segment users when sending emails. Currently, a contact
can only be in one user group. [Read more](/contacts/properties#user-group)
A unique user ID (for example, from an external application). [Read
more](/contacts/properties#user-id)
Key-value pairs of mailing list IDs and a `boolean` denoting if the contact
should be added (`true`) or removed (`false`) from the list. [Read
more](/contacts/mailing-lists#api)
```json
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": false
}
```
### Custom properties
You can also include [custom contact properties](/contacts/properties) in your request body. These should be added as top-level attributes in the request.
Custom properties can be of type `string`, `number`, `boolean` or `date` ([see allowed date formats](/contacts/properties#dates)).
```json
{
"email": "hello@gmail.com",
"plan": "pro", /* Custom property */
"favoriteColor": "Blue" /* Custom property */
}
```
There are a few [reserved names](/contacts/properties#reserved-names) that you cannot use for custom properties.
To empty or reset the value of a contact property, send a `null` value.
## Response
### Success
The ID of the contact.
### Error
An error message.
```json Response
{
"success": true,
"id": "id_of_contact"
}
```
```json Error response
{
"success": false,
"message": "An error message."
}
```
# Contact activity timeline
The contact activity timeline is a great way to see all the activity for a specific contact.
![contact property timeline](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/contact-activity-timeline.png)
The contact activity timeline provides a chronological view of all the activity for a specific contact. To access the contact activity timeline, click on a contact from inside an audience.
Email properties that can show on the timeline include:
* Sent
* Opened
* Clicked
* Soft bounced
* Hard bounced
* Marked as spam
* Unsubscribed
Additionally, we also show the following properties:
* Added to audience
* Event fired
# Filters and Segments
How to send emails to specific groups of contacts and save segments for future use.
After you have added contacts to your audience in Loops, you may want to send loops or campaigns to certain groups of contacts.
You can do this with filters and segments.
![Loop](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/audience-filters.png)
## Audience filters
When sending [campaigns](/types-of-emails#campaigns) or emails inside [loops](/loop-builder), you can send to specific groups of contacts in your audience.
Choosing these contacts is done using filters, which are based on [contact properties](/contacts/properties) (either default properties or custom properties you've added to your audience).
![Audience filter form](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/filter-form.png)
You can add multiple filters at once, and you can also choose to apply *all filters* ("All of these are true") or *any filter* ("Any of these are true").
Audience filters are automatically updated as contact properties are changed. This means that your emails will only send to contacts that match the filter at the time the email is sent.
## Audience segments
Segments are just filters that are saved in your Loops account for the future. This makes them easily re-usable between different loops and campaigns.
You can create segments while sending campaigns or loops, or directly on the [Audience page](https://app.loops.so/audience).
To create a segment, first filter the audience table and then click **Save segment**.
![Create a segment](https://mintlify.s3-us-west-1.amazonaws.com/loops/contacts/images/create-save-segments.png)
You will be prompted to add a name for your segment, then click **Finish**.
Your new segment will then be available in a dropdown whenever you filter your audience for campaigns or loops.
![List of segments](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segments.png)
Just like filters, segments are automatically updated when contact data is changed, meaning emails always send to the correct contacts at time the email is sent.
# List management
Organise contacts and offer a subscriber preference center with mailing lists.
Lists are the preferred way of managing your contacts in Loops.
In addition to providing fine-grained control over your audience, using Lists will automatically generate a branded Preference Center for contacts in your audience, allowing them to easily manage their subscription preferences.
Lists can be public or private and contacts can belong to many, one, or no lists.
Lists are an optional feature. You can use Loops without lists but if you'd
like finer-grained control over your contacts and the types of communication
they receive, lists are available on any plan tier.
## List visibility
Each list you create can be Public or Private.
By default lists are private, meaning they are only shown to their subscribed contacts (non-subscribers won't be able to see or subscribe to private lists in the Preference Center).
If you want to allow general opt-in to a list, you can set the list visibility to `Public`. Public lists will be shown to all contacts in the Preference Center.
You can also sign up new subscribers to public lists with [Forms](/forms).
Both private and public lists are visible within your Loops admin and can be
used for filtering contacts when sending campaigns and loops.
## Preference Center
The Preference Center allows your contacts to manage their own subscription preferences.
![Preference Center](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/preference-center.png)
A link to the contact-specific Preference Center is automatically added to each marketing email sent from Loops. You can link to the Preference Center in MJML emails by using the `{unsubscribe_link}` [dynamic tag](/creating-emails/personalizing-emails#dynamic-tag-syntax).
You can upload a company icon to brand your Preference Center. This option is shown just below your mailing lists in the [Lists settings page](https://app.loops.so/settings?page=lists).
You can brand your unsubscribe page with a company icon even if you do not use
the lists features.
Within the Preference Center, contacts will see:
* your company icon (if uploaded)
* the names and descriptions of all public lists
* the names and descriptions of all private lists they are subscribed to
* the option to unsubscribe from each list they are subscribed to
## Create a list
Go to [Settings -> Lists](https://app.loops.so/settings?page=lists).
Click on the **Create a list** button.
![Create a new list](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/create-list.png)
A new mailing list will appear. Enter a name for your list and optionally, a description.
You can also choose a color to easily identify the list inside your Loops account.
![Visibility toggle](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/lists-toggle.png)
Choose between `Private` or `Public` ([see above](#list-visibility)).
Click **Save changes** to finalize the creation of the list.
## Edit a list
To edit an existing list, go to [Settings -> Lists](https://app.loops.so/settings?page=lists).
Edit the name, description, visibility and color.
Click **Save changes** to apply the changes.
After saving your changes, the updated list data will be instantly available
to your contacts in their Preference Centers.
## Utilizing lists
Here are a few ways you can use lists to send emails and organise contacts.
### Trigger a loop when a contact is added to a list
This example is a typical use case of sending an email sequence to new contacts when they are added to a specific list.
[Create a loop](/loop-builder) or edit an existing one.
Set the Loop trigger to "Contact added to list". ![Select
trigger](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/set-trigger.png)
Select the list you want to trigger the loop. ![Select the
list](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/select-list.png)
Start the loop. When a contact is added to the selected list, the loop will
be triggered.
### Send campaigns to a list
Instead of sending campaigns to your whole audience, you can send emails to a specific list.
[Create a campaign](https://app.loops.so/campaigns) or edit an existing one.
On the [Audience page](https://app.loops.so/audience), select the list you want to send to.
![Select a mailing list](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/campaign-list.png)
Users not subscribed to the selected list will not receive the campaign.
Optionally, you can apply additional [filters or segments](/contacts/filters-segments) to further refine your audience.
### Manually add contacts to lists
How to add existing contacts to your different mailing lists within Loops.
You cannot edit the list subscriptions of contacts who have been unsubscribed
from your audience. Likewise, if a contact unsubscribes from a list via the
Preference Center, they cannot be resubscribed by your team.
#### Individual contacts
Go to your [Audience page](https://app.loops.so/audience).
Click on the contact you want to manage.
In the contact details page, click on **Subscribed** to reveal the mailing
list dropdown.
![Manage subscriptions](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/manage-contact-subscriptions.png)
Toggle each list on or off as needed. Click **Save changes** in the top
right to apply the changes.
#### Bulk contacts
You can easily add any filtered group of contacts to a specific list on the Audience page.
Go to your [Audience page](https://app.loops.so/audience).
Add filters to segment your audience into the group of contacts you'd like
to add to a list.
Click the `•••` menu icon on the far right-hand side of the audience filters,
select **Add to mailing list** and then select the list(s) you want to add the contacts to.
![Add to list](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/bulk-assign-to-lists.png)
### Upload a CSV to a list
If you want to import contacts to a list in bulk you can use our [CSV importer](/add-users/csv-upload).
In the final stage of the form you can select a list, which will add all contacts (new or existing) in the CSV file to that list.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/csv-upload.png)
### Add contacts to lists with the API
Utilizing the [Loops API](/api-reference) you can programmatically add and remove contacts to and from Lists.
When creating a contact, updating a contact, or sending in an event with the API, you can include a `mailingLists` object in the payload.
This `mailingLists` object is a key-value pair of list IDs and a subscription status. The subscription status can be `true` or `false`.
```json
{
"email": "loopy-loop@example.com",
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": false
}
}
```
In this example, the contact would be subscribed to `cm06f5v0e45nf0ml5754o9cix` and unsubscribed from `cm16k73gq014h0mmj5b6jdi9r`.
Mailing list IDs can be found [in the app](https://app.loops.so/settings?page=lists) (click the ID to add it to your clipboard) or by using the [API](/api-reference/list-mailing-lists).
![Visibility toggle](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/lists-toggle.png)
### Add contacts to lists with forms
If you use a [form](/forms/simple-form) on your website you can subscribe contacts to specific lists.
When exporting HTML from the [Forms page](https://app.loops.so/forms) in Loops, choose a list from the **Settings** tab.
![Select a list from the form settings](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mailing-lists/form-settings.png)
Adding contacts to a list via a form only works with public lists. The option
to select a list will only appear in the form settings if you have at least
one public list.
If you already have a form in place or are using a [custom form](/forms/custom-form) you can add a `mailingLists` parameter to the form body with the value a comma-separated list of mailing list IDs.
HTML example:
```html
```
JavaScript example:
```javascript
fetch(formEndpointUrl, {
method: "POST",
body:
"mailingLists=" +
encodeURIComponent("cm06f5v0e45nf0ml5754o9cix,cm16k73gq014h0mmj5b6jdi9r") +
"&email=" +
encodeURIComponent(emailInput.value),
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
```
# Contact properties
How to add, edit and delete contact properties.
## Default contact properties
These are the default properties for every contact on Loops. They cannot be deleted.
| Contact Property | Example | Email Tag\* | API Name\*\* |
| ---------------- | --------------------------------------- | ------------- | ------------ |
| Email | *[hi@example.co](mailto:hi@example.co)* | `{email}` | `email` |
| First Name | *Chris* | `{firstName}` | `firstName` |
| Last Name | *Frantz* | `{lastName}` | `lastName` |
| Notes | *Favorite color is blue.* | `{notes}` | N/A |
| Source | *API* | `{source}` | `source` |
| Subscribed | `true` | N/A | `subscribed` |
| User Group | *Investors* | `{userGroup}` | `userGroup` |
| User Id | *ask523236* | `{userId}` | `userId` |
\* Used to [add personalization to emails](/creating-emails/personalizing-emails#dynamic-tag-syntax).\
\*\* Used in [API requests](/api-reference).
### Source
"Source" describes where the contact originated from.
By default, this value will be "Form" for contacts added [via a form](/forms/simple-form), or "API" for contacts added [via the API](/api-reference). You can specifiy custom "Source" values when adding contacts via forms and the API.
### Subscribed
The "Subscribed" value determines whether a contact is able to receive **loops and campaigns**. Unsubscribed contacts *will receive all transactional emails*.
Contacts can unsubscribe from your emails using an Unsubscribe link automatically added to your campaigns and loops.
Some important notes:
* We do not charge for unsubscribed contacts.
* We suggest you keep unsubscribed contacts in your audience. If you delete and then re-add them in the future somehow, they may end up being "subscribed" even though they have been unsubscribed.
* You cannot re-subscribe contacts via a [CSV upload](/add-users/csv-upload) or from the Audience page in Loops. You can re-subscribe contacts [with the API](/api-reference/update-contact) and with some of [our integrations](/integrations#manage-contacts).
### User Group
"User Group" is a useful optional property that you can use to segment contacts. It is a free text field that allows you to easily divide contacts into groups like "Users", "VIPs", "Investors" or "Customers".
Contacts can currently only have one user group value.
### User Id
"User Id" is a unique external ID you can assign to each contact in your audience. For example, this could be a customer ID from your store or a user ID from your SaaS.
This field is optional but is very useful if you are working with our API. For example, you need a user ID to be able to [change a contact's email address](/api-reference/update-contact).
## Custom contact properties
Custom contact properties are additional fields that you can create to store information about contacts.
### Types of property
Custom contact properties can be one of four different types:
* String
* Number
* Boolean
* Date (see below)
You can specify a property type when creating new properties in Loops.
#### Dates
When sending dates with the [API](/api-reference) or via one of our [integrations](/integrations), you can use either a Unix timestamp (*in milliseconds*) or an [ECMA-262 date-time string](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format)
Timestamps must be in milliseconds and can be sent as either an integer or string.
* `1705486871000` (if the Unix timestamp is `1705486871`)
Supported date formats are shown below. These must be sent as a string. Adding a time offset at the end (e.g. `+02:00` or `-07:00`) is optional (if omitted, the date will default to UTC).
* `YYYY-MM-DDTHH:MM:SS.sss`
* `YYYY-MM-DDTHH:MM:SS`
* `YYYY-MM-DDTHH:MM`
* `YYYY-MM-DD HH:MM:SS.sss`
* `YYYY-MM-DD HH:MM:SS`
* `YYYY-MM-DD HH:MM`
* `YYYY-MM-DD`
### Reserved names
Note that Loops does not allow the creation of properties with the following reserved names:
* `id`
* `listId`
* `softDeleteAt`
* `teamId`
* `updatedAt`
### Add a property
One way to create custom contact properties is to go to [your Audience](https://app.loops.so/audience) and click on any of the column headers, then select **Add property**.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/option-1.png)
Alternatively you can scroll to the end of the Audience table and click the `+` button at the end of the column headers.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/option-2.png)
A third way is to go your [API Settings](http://app.loops.so/settings?page=api) page, scroll down to the Contact properties section and click **Add property**.
In each of these cases, you'll see a form asking you for a property name and type.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-property-form.png)
### Deleting contact properties
You can delete properties on the Audience page by clicking on column headers.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/delete-property-dropdown.png)
You can also delete properties from your [API Settings](http://app.loops.so/settings?page=api) page by clicking the trashcan icons.
It is not possible to delete default contact properties.
Once a contact property is deleted, all associated data will also be deleted and cannot be recovered. It's important to be sure that you won't need the information stored in a property before deleting it.
#### Property in use warning
If you receive a “Property in use” warning modal while deleting a contact property, there are a few things you can check before you're able to delete the property.
* If the listed email is a Campaign:
* Check if the property is in use as [dynamic content](/creating-emails/personalizing-emails) inside the email editor
* Ensure this property is not being actively used in the Audience filter
* If the listed email inside a Loop:
* Make sure a draft or running Loop is not using it as part of the Audience filter or as a Trigger
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/delete-property.png)
# Components
Create re-usable elements for your emails.
Components are re-usable elements for emails. They help you create frequently-repeated sections of emails once, which you can then easily drop into new emails.
![Components in an email](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/components-example.png)
Changes made to components can be synced to all other instances. You can also choose to make local edits to a single component instance without updating others.
Components can be created from and added to all emails created in Loops (campaign, loops and transactional emails). They also work in both Plain and Styled emails.
## Example components
Some useful examples of components are logos and social icons. These elements are typically the same across multiple emails; using components will make sure they are the same everywhere.
Most of the time you will want your logo to have the same alignment, spacing and size in your emails. Similarly, you will want the same set of social icons readily available to drop into every new email you create.
![Example components](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/example-components.png)
## Create a component
To create a component, click on the block settings icon on the left side of an element in the editor. Then click **Create component**.
![Create a component](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-component.png)
A modal will appear where you can name your component. Use a descriptive name so you can easily find your component in the future.
Click **Create**. You will see your new component appear in the Components list on the left of the editor.
All components you create are available in all of your emails, i.e. a component created in a campaign email is also available to insert into transactional emails.
## Insert a component
Click on **Components** at the top of the left-hand menu to reveal your components list, then simply click on a component to insert it.
![Add a component](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/insert-component.png)
If you want to change the location of a component in your email, you can drag and drop it within the editor just like other blocks.
If you already have a component in your email, clicking **Duplicate** in the block settings menu will add a copy of that component into the email, including any local edits made.
## Edit a component
You can tell if an element in your email is a component by looking for a purple outline around the block in the editor. You will also see a purple label containing the component's name just above the formatting toolbar.
To edit a component, edit its content as you would any other part of your email.
This will create local edits to that single instance; these edits are not synced to other components in use elsewhere. This means you can make tweaks and changes to a single instance of a component without updating all other instances.
If a component has local edits, you will see a purple dot in the components icon in the formatting toolbar.
![Edited component](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/edited-component.png)
If you want to save your changes to all instances of the component, click on the block settings icon and then click **Push changes**. Note that any local edits made to the component in other emails will be preserved.
![Push changes to other instances](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/push-changes-1.png)
Alternatively, you can click on the component, click on the components icon on the far right of the formatting toolbar (you'll notice a purple dot denoting that the component has edits), then click **Push changes to main component**.
![Push changes to other instances](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/push-changes-2.png)
If you make local edits to a component that you want to revert, you will find a **Reset all changes** option in both the block settings menu and formatting toolbar.
## Rename a component
In the Components list, find the component you want to rename, then click the `•••` menu icon. Click on **Rename** to show the rename modal.
Enter a new name and click **Rename**.
## Delete a component
Deleting a component only deletes the component; it does not remove the component from emails.\
A deleted component's contents will be retained by any email it was added to.
In the Components list, find the component you want to rename, then click the `•••` menu icon. Click on **Delete** to show the confirmation modal.
Click **Delete** to delete the component.
# Duplicating emails
Re-use basic elements of an email or create email templates.
Duplicating emails is a great way to save time crafting similar emails
You can easily create emails that share many of the same elements (investor updates, product
updates, waitlist invites, etc).
To duplicate an email:
1. Go into Campaigns, Loops, or Transactional (whichever email you want to duplicate).
2. Click the `•••` menu icon and select **Duplicate**.
3. Edit the new email's subject line, preview text and content as needed.
![Duplicating emails](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/duplicating-emails.png)
# Adding content
Learn how to edit emails in the Loops editor.
## Formatting text
Once you have written content in your email, you can apply styles by highlighting the text.
This will bring up a formatting toolbar with options that give you a lot of control over your written content.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/formatting-toolbar.png)
You can choose between different headings, style text **bold**, *italic*, underline as well as add links. You can also change text size and color.
Text can also be easily changed into lists, quotes and inline code blocks.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/editor-text.png)
## Adding elements
Emails can be more than just text. You can add the following elements to your emails:
* images
* buttons
* dividers
* social icons
* columns
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/editor-elements.png)
You can add elements by typing `/` in the editor.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/slash-menu.png)
If you continue typing, you can narrow down the selections. You can use your arrow keys to select items and pressing Enter will confirm your selection.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/slash-typed.png)
You can alternatively add elements from the toolbar above the editor, or by hovering over an existing element in your email and clicking the `+` plus icon on the left.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/editor-adding.png)
### Images
As well as adding from the toolbar or the `+` icon, you can drag or paste images into the editor.
Add a link to an image by selecting the element and then clicking the link icon in the toolbar.
#### Dynamic images
Uploaded images can become dynamic by selecting them and then clicking the `⚡️` icon in the formatting toolbar. Paste in an image URL or add dynamic content.
For example, you could insert an `imageUrl` data variable in a transactional email, or use an `avatarUrl` custom contact property in a campaign.
![Adding a dynamic image](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/dynamic-image.png)
You can also create dynamic URLs by combining text and dynamic content inside the image source field.
![Adding a dynamic image URL](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/dynamic-image-url.png)
Keep in mind that the image must be publicly accessible for this to work and the URL must end with a supported image file extension for email (like `.jpg` or `.png`). Additionally, these images should be hosted for a period of time that is relevant to the email's lifecycle as they will not be stored in Loops.
Note that, just as with other dynamic content, if the contact or event
property used for your dynamic image is missing, the email will not be sent.
### Buttons
Buttons let you add call-to-action elements inside your emails.
Add links to buttons by selecting the element and then clicking the link icon in the toolbar.
### Dividers
Dividers help separate or group content in your emails. Change spacing around dividers by clicking the drag-and-drop icon on the left and changing the padding values ([more about block settings below](#block-settings)).
### Social icons
You can add a row of social icons by clicking the star icon in the editor toolbar.
![Social icons](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-icons.png)
You have options for icon width and color (black, grey or white) plus padding. You can add more icons by clicking the plus icon. Drag icons to rearrange them.
To change the alignment of the icons, click on the block settings icon (more info below).
### Columns
Columns allow you to arrange content side by side, creating dynamic layouts for your emails. You can use columns to place elements like images, text, buttons, and more next to each other. Currently, we support a maximum of two columns. Nesting columns within columns is not yet supported.
#### Adding columns
You can add columns to your email in several ways:
1. **Using the `/` slash menu in the editor**: Type `/` to open the slash menu then start typing "columns" or click on the **Columns** option.
2. **Using the editor toolbar**: Click on the columns icon to insert a column layout.\
![Adding columns from toolbar](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/columns-toolbar.png)
3. **Dragging two blocks together**: Click and hold the block settings icon (six dots) to the left of a block. Drag the block next to another one until you see a vertical gray line on the right, which indicates a new column will be created.
![Adding columns by dragging blocks together](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/columns-dragging.png)
#### Customizing columns
Once you've added columns, you can customize their appearance and behavior to suit your design needs.
**Width and spacing**
You can adjust the width of a column by clicking and dragging the gray bar between the columns.
![Adjusting column width](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/column-width.png)
You can also adjust how much space appears between columns by dragging the green bar that appears on hover.
![Adjusting column spacing](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/column-spacing.png)
**Stacking columns on mobile**
When emails are viewed on a mobile device (when there is less horizontal space available) you can choose if your columns should stack vertically for better readability or stay as columns.
In [block settings](#block-settings) (click on the drag-and-drop icon to the left) you'll find **Stack columns** (the default) and **Preserve columns** options.
If **Stack columns** is selected, columns will be stacked when the viewport is 479px or smaller.
![Mobile stacking option](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/mobile-stacking.png)
**Adding and moving content**
You can drag elements like text blocks, images, and buttons in and out of your columns.
To do this, hold down the `Cmd` key (Mac) or `Ctrl` key (Windows) while hovering over the element you want to move. Then click and drag the block settings icon (six dots) to move the block to its new position.
![Drag an element into a column](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/drag-into-column.png)
#### Editing column content and settings
Columns consist of multiple layers—the outer container and the inner column blocks. You can style both layers individually.
**Outer container settings**
Click on the drag-and-drop icon of the column block without holding any keys to access the outer container settings. Here, you can set the background color, padding, border radius, and alignment for the entire columns section.
**Inner column settings**
To edit the settings of an individual column or the elements inside it, hold down the `Cmd` key (Mac) or `Ctrl` key (Windows) while clicking on the element. This allows you to "drill through" the layers and select the block settings for the inner element.
#### Tips
* **No nested columns**: Keep in mind that nesting columns within columns is not supported. If you need a complex layout, consider adjusting your design to fit within the two-column limit.
* **Consistent styling**: Use the block settings to ensure that padding and alignment are consistent across your columns for a polished look.
## Block settings
Block settings let you edit properties of different element "blocks" in your email.
If you hover over a block in your email, you'll see a drag-and-drop icon appear on the left.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/block-icons.png)
You can drag this icon to re-order elements in your email.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/block-drag.png)
If you click this icon you will open the block settings menu. Here you'll see styling options for padding, radius, background color and horizontal alignment.
You can also duplicate and delete blocks from this menu.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/block-menu.png)
## Footer content
We add an automatic footer into campaign and loops emails, which includes your company name, address and an unsubscribe link.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/footer.png)
Unsubscribe links help prevent your messages from being marked as spam and ensure that your messages are willingly being received by an engaged audience, helping your deliverability.
The unsubscribe link leads to a [Preference Center](/contacts/mailing-lists#preference-center), where your contacts can manage their own subscriptions.
You can edit your company address from [Settings > Domain](https://app.loops.so/settings?page=domain).
# Font support
Font support via Google Fonts is now available in Loops.
## Web font support
Custom font support via Google Fonts is now available in Loops. You can use any font from Google Fonts in your emails. To use a font, simply select it from the font dropdown in the email editor. Please note that not all fonts are supported by all email clients. See the table below for a list of supported email clients.
| Support | Platform |
| ------- | ---------- |
| No | Gmail |
| No | Outlook |
| Yes | Apple Mail |
| Yes | Samsung |
| Yes | Comcast |
| No | AOL |
| No | Yahoo |
## General list of email-safe fonts
The following fonts are supported by all modern email clients. They're considered "email safe" fonts because they're available on most devices and email clients.
* Arial
* Courier New
* Georgia
* Lucida Sans Unicode
* Tahoma
* Times New Roman
* Trebuchet MS
* Verdana
# Personalizing emails
Add context and personalization to emails.
Every email you send from Loops can contain dynamic content connected to the contact you're sending to or the event that triggered the email.
## Types of dynamic content
The three [email types](/types-of-emails) in Loops have different dynamic content available to them:
* **Campaign emails** can contain **contact properties**.
* **Emails within Loops** can contain **contact properties** and **event properties**.
* **Transactional emails** can contain **data variables**.
The three types of dynamic content are:
* **Contact properties** are pieces of data related to each [contact](/contacts/properties) in your audience. There are a set of default properties like name and source, but you can also add any number of custom contact properties. If you sync contact data to Loops with the API, an integration or with CSV uploads, you can include that data in your email.
* **Event properties** are pieces of data that can be sent along with every [event](/events) (which are used to trigger loop emails) via integrations or API calls.
* **Data variables** are pieces of data included in [transactional emails](/transactional), which are populated in the API call.
## Add dynamic content to emails
If you want to add dynamic content to a [custom MJML email](/creating-emails/uploading-custom-email), check the [Dynamic tag syntax](#dynamic-tag-syntax) section below.
To add dynamic content to emails, simply select the corresponding icon in the toolbar of the email editor.
![Adding a contact property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/basic-merge.png)
Depending on whether you're editing a campaign, loop or transactional email, you will have different options (explained above).
When the email is sent, the dynamic content will be replaced with actual values from the contact, event or data variable.
If you send an email and the dynamic content is missing a value, the email will not be sent. Make sure to add fallback values to avoid missed sends.
A common example of using dynamic content is to personalize an email greeting by using a contact's first name.
Once you've clicked on the icon in the toolbar, select the contact property you want to add. In this case, **First Name**.
![Selecting the First Name property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/editor-appear.png)
When the email is sent, the contact's data will be added to your email, like this: `Hey Chris,` (if the contact doesn't have a First name value, it will read `Hey there,`).
## Custom properties
Any contact attributes you sync with Loops either through the [API](/api-reference) or through one of our [integrations](/integrations) can be added to an email to personalize it.
Likewise, any data variables you add to your transactional emails, or event properties you add to your events, will also appear as options in the editor.
For example, say you wanted to create a [Scheduled digest](/guides/scheduled-digest-email) email with metrics about a contact over the last week. You could sync those metrics to Loops as [event properties](/events/properties).
These properties will automatically be available to insert into any emails triggered by that event.
![Inserting an event property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/merge-tag-menu.png)
## Fallback values
It is important to set a fallback variable for any dynamic content you add to your campaign and loop emails.
If a contact does not have a value for the related contact property, or you don't remember to include an event property for an event-triggered email, the email will fail to send.
Fallback values can be used to make sure default content is added to the email and ensure that it is sent.
For example, if you set a fallback variable for “First Name” as “there”, if a contact does not have this contact property, the email will include “there” in the place of the contact's name.
This is a great way to make sure that your emails still feel personalized to contacts even if there is no property available.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/fallback-variable.png)
## Dynamic tag syntax
As well as adding dynamic content using the toolbar icons, you write "tags" directly in the email body. This is especially useful when [uploading custom emails](/creating-emails/uploading-custom-email).
These tags are the only way to add dynamic content in [custom MJML emails](/creating-emails/uploading-custom-email).
### Contact properties
If you have a custom contact property named `teamName` that you want to add to a campaign, you can write it surrounded by curly brackets in the email:
```
{teamName}
```
When the email is sent, the `teamName` value for each contact will be added to the email.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/merge-tag-0.png)
For a list of all of your contact properties, visit the [API Settings](https://app.loops.so/settings?page=api) page. The **API Name** is the name you use within the brackets in your email, for example `{firstName}`, `{lastName}`, `{email}`, etc.
![Contact properties table](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/merge-tag.png)
### Event properties
To add dynamic data to emails within loops using event properties, the tag requires an `EVENT_PROPERTY:` prefix:
```
{EVENT_PROPERTY:firstName}
```
### Data variables
To add data variables in transactional emails, the tag requires a `DATA_VARIABLE:` prefix:
```
{DATA_VARIABLE:firstName}
```
It's important to use camelCase format to type your tags. If you have
any questions about how to format your tags, reach out to us!
# Managing styles
Learn how to edit emails in the Loops editor.
## Styled vs Plain emails
Loops offers two different email styling options, Styled and Plain.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/styled-plain.png)
By default new emails are created as "Styled" emails in the editor. This option offers a range of design options that can be used to design the base theme for your email, like text and background colors, padding and borders.
A Styled email layout is a responsive central column with a maximum width of 600 pixels.
Plain emails are full-width emails with no base design options (though you can always style individual content as described at the top of this page). Plain emails better mimic emails sent from clients like Gmail and Apple Mail.
## Style panel
If the Styled option is enabled (see above), you will see a Style panel when clicking the pencil icon.
This panel shows options for changing base styles for your email.
This includes all text, headings, links, buttons and dividers in your email, as well as design options for the main email body (padding, background and border).
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/message-visual.png)
Any changes you make in the style panel will be applied to all matching elements in your email.
If you want, you can always edit specific elements individually from their own formatting toolbar. (However, if you make changes in the email's style panel afterwards, individual styling will be overwritten.)
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/edit-button.png)
There are helpful "Reset to default" icons if you ever want to return styling back to Loops' default.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/reset-style.png)
### Language selector
We've included a helpful language selector in the style panel. Using this will tell email clients which language your emails are written in.
This increases the accessibility of your emails, plus some email clients may use this language information to auto-translate email content or offer translation options.
The language selector does not have a default value. We recommend selecting the correct language for each of your emails.
![Language selection menu](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/language-picker.png)
If you send campaigns and loops in different languages, we recommend using a [custom contact property](/contacts/properties#custom-contact-properties) to store language information for each contact. Then, when it comes to sending emails, create emails in different languages (using the language switcher to specify the language), and [filter your audience](/contacts/filters-segments#audience-filters) for each email to match the language stored for each contact.
For transactional emails, create a new email in each required language. You will need to store language information for each recipient in your application and map transactional IDs to their respective language groups.
## Saved styles
Saved styles let you create repeatable styles that can be easily applied to new emails.
Once applied, Saved styles can be tweaked on each email and changes will also be synced back to the main style set. This makes the same change on any other email that the styles are applied to.
If your email is in Plain mode (see above), styles cannot be applied.
### Create a Saved style
To create a Saved style, click the `+` plus icon in the style panel.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-style.png)
Give your style a name and click the `âś“` check icon or press Enter. This will create a Saved style based on the current styling options selected in the style panel and apply it to the current email.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/save-style.png)
You can now add this Saved style to other emails.
### Apply a Saved style to an email
To add an existing style to an email, open the style panel and select a Saved style from the dropdown.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/select-style.png)
### Edit a Saved style
To edit a Saved style, first open an email with it applied, or apply it to an email. Then change individual style options to your liking.
When individual styles are changed, you'll notice they are highlighted in purple, which denotes styles that have deviated from the main Saved style.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/edited-style.png)
A purple "Update" button also appears. Clicking this button updates the Saved style and also *applies the changes to all emails that have the Saved style applied*. This makes it really easy to change styles across many emails at once.
Alternatively you can create a new Saved style based on your changes by clicking the `+` plus icon.
This new Saved style will be applied to the current email. (Emails using the previous Saved style will retain that Saved style's settings.)
### Make one-off changes to a Saved style
You are free to make one-off custom design changes on an individual email. Just avoid clicking the "Update" button shown above as this will sync the changes to all other emails using the Saved style.
Any subsequent updates made to the underlying Saved style will be synced to your email but your individual style changes made directly on the email will override any synced changes.
### Reset to a Saved style's defaults
After making design changes to an email with a Saved style applied, you can get back to the Saved style's defaults by clicking the reset button next to the "Saved" title.
This will re-apply the Saved style's design to your email and remove *all* custom edits.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/reset-saved-style.png)
### Remove a Saved style from an email
To remove a Saved style from an email click on the `–` minus icon in the panel.
This will revert back to any styles directly applied to the email before the Saved style was applied.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/remove-style.png)
### Duplicate a Saved style
You can easily duplicate a Saved style if you want to create a similar style for different emails.
Open an email with a Saved style applied, click the `•••` menu icon and select **Duplicate**.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/duplicate-style.png)
Give your new Saved style a new name then click the `âś“` check icon or press Enter to save.
This will create a new Saved style using the current styles and apply it to your email.
### Delete a Saved style
To delete a Saved style from your account, make sure the style is applied to the email you have open and then click the `•••` menu icon and select **Delete**.
To make sure there are no design changes to emails in your account, the settings from the deleted Saved style will get applied individually to each email it was active on.
However, please note that any overrides made to the saved style in the affected emails will still be retained even after the style is deleted.
# Uploading a custom email
Use Loops with Emailify, Email Love or MJML.
While we do support importing MJML, we recommend using our editor to create
your emails. It's the easiest way to create beautiful emails that work across
all email clients.
## Overview
We allow uploading of custom-coded emails created using a markup language called MJML.
You can upload custom MJML for [all three types of emails](/types-of-emails) in Loops (campaigns, loop emails and transactional emails).
**MJML**
MJML is a markup language that helps you create responsive emails. It's an established framework that helps you create beautiful emails that work across all email clients. You can read more about it at [mjml.io](https://mjml.io/)
**Figma** (via the Emailify and Email Love plugins)
Sometimes you just want that special touch to an email that only Figma can give you. We get it! That's why we support plugins [Emailify](https://www.figma.com/community/plugin/910671699871076601/emailify-html-email-builder) and [Email Love](https://www.figma.com/community/plugin/1387891288648822744/email-love-html-email-builder), which help you create beautiful emails in Figma then export into Loops.
## MJML
If you have your MJML ready, there is one step you need to complete before you can upload it into Loops...
### Add an unsubscribe URL
In your email code, you have to insert an unsubscribe link. This keeps you compliant with email sending restrictions.
All you need to do is add a `{unsubscribe_link}` tag into your MJML. When the email is sent, we will insert a contact-specific URL into this tag, which the contact can click to unsubscribe.
```HTML
Unsubscribe
```
### Add dynamic content
You may want to add dynamic content (for example, a contact property or event property) into your email. You can do this using dynamic content tags.
When the email is sent, Loops will replace this tag with the actual value.
Remember to use camelCase format when typing your event property tags.
For example, adding a first name [contact property](/contacts/properties) (in campaigns and loops) can be added like this:
```
Hello {firstName},
```
In loops triggered by events you can add [event properties](/events/properties) with an `EVENT_PROPERTY:` prefix:
```
Hello {EVENT_PROPERTY:firstName},
```
In transactional emails you can add [data variables](transactional/guide#add-data-variables) with a `DATA_VARIABLES:` prefix:
```
Hello {DATA_VARIABLE:firstName},
```
[Read more about dynamic content tags](/creating-emails/personalizing-emails#dynamic-tag-syntax)
## Emailify
Using Emailify, you can create well-designed emails inside Figma, then easily export them ready for Loops.
Download the free [Emailify plugin for Figma](https://www.figma.com/community/plugin/910671699871076601/emailify-html-email-builder) and launch it.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emailify-plugin.png)
### Add blocks to your email
To build your email you can drag and drop pre-made blocks provided by Emailify.
Once added you can customize each block.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emailify-blocks.png)
Loops will automatically download and host all of your email images so they
can be reliably displayed to your audience. This feature results in an odd
quirk that you should be aware of:
Any text in your email that matches the path to one of your images will be replaced with the new path provided by loops.
**For example:** `img/myImage.jpg` will be replaced with something like: `https://something.com/lkjn98s08hbAF/img/lkwekHBlhk78kasj.jpg`
For most situations this won't be an issue, only text that exactly matches the path to one of your images will be replaced.
### Add dynamic content
You may want to add dynamic content (for example, a contact property) into your email. You can do this using dynamic content tags.
For example, adding a first name value can be added like this:
```
Hello {firstName},
```
In loops you can add event properties with an `EVENT_PROPERTY:` prefix:
```
Hello {EVENT_PROPERTY:firstName},
```
In transactional emails you can add data variables with a `DATA_VARIABLES:` prefix:
```
Hello {DATA_VARIABLE:firstName},
```
[Read more about dynamic content tags](/creating-emails/personalizing-emails#dynamic-tag-syntax)
### Add the Loops footer
While creating your email, you need to include an unsubscribe link.
To do this manually, add a link with the URL `{unsubscribe_link}`.
Alternatively, Emailify contains a pre-made Loops footer. Click **Footer**, scroll down until you see the Loops logo and click.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emailify-footer.png)
You are then free to edit the text and design of the footer (just leave the link URL value as-is).
### Export your email
When you're ready to export, click on **Export HTML** in the top right.
Then in the dropdown select **Loops**, which will generate Loops-friendly MJML.
You can add a Subject and Preview text in this step, too.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emailify-export.png)
When you're ready, click the **Export for Loops** button and wait for the code to be generated.
To download your files click on the **Download your .zip file** button.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emailify-download.png)
## Email Love
Email Love is a Figma Plugin that enables you to design and export responsive and accessible HTML emails directly from Figma. Email Love includes an “Export for Loops” option that downloads an MJML file that can easily be imported into Loops.
[Download the Email Love Figma Plugin](https://www.figma.com/community/plugin/1387891288648822744/email-love-html-email-builder)
![Email Love Figma plugin](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emaillove-plugin.png)
To run the plugin, click the **Actions** menu in the Figma toolbar, then under the **Plugins & Widgets** tab select **Email Love -> HTML Email Builder**.
### Add components to your email
You can now start designing your email template using Email Love’s pre-built components.
Select the frame you created in the previous section (where you want components to be added). From the plugin pane select one of the component types and then the component you want to add.
![Adding components](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/emaillove-components.png)
### Customize components
You can customize every component you add to your design. Each component features layers and frames that replicate the structure of MJML. For example, selecting **mj-section** in a header component enables you to update the background color and selecting **mj-image** in the header enables you to update the logo.
Go through each component and update the text, images, and styles as you wish.
### Add an unsubscribe link
For campaign and loops emails you need to include an unsubscribe link in your email.
If you add a **Footer** component Email Love will automatically add a Loops unsubscribe link at the time of export.
Alternatively you can code an unsubscribe link manually by adding a link element with the URL `{unsubscribe_link}`.
```HTML
Unsubscribe
```
### Add dynamic content
You may want to add dynamic content (for example, a contact property) into your email. You can do this using dynamic content tags.
For example, adding a first name value can be added like this:
```
Hello {firstName},
```
In loops you can add event properties with an `EVENT_PROPERTY:` prefix:
```
Hello {EVENT_PROPERTY:firstName},
```
In transactional emails you can add data variables with a `DATA_VARIABLES:` prefix:
```
Hello {DATA_VARIABLE:firstName},
```
[Read more about dynamic content tags](/creating-emails/personalizing-emails#dynamic-tag-syntax)
### Export for Loops
When your email is finished, click on the frame you want to export. Click **Export** and select "Loops" from the **Export** dropdown. Then click **Export to Loops** to generate a ZIP containing MJML and any included images, which you can then upload into Loops.
## Upload into Loops
Once you have MJML with an unsubscribe link included, you can upload it into Loops.
Click the upload icon above the email editor on the **Compose** page.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/import-mjml.png)
If you exported from Emailify, open the ZIP you downloaded. Drag and drop the `.zip` file found inside the **\_zips (For upload to Loops.so)** folder. Then click **Upload**.
If you exported from Email Love, upload the generated `.zip` file then click **Upload**.
If you have custom MJML, create a ZIP file and drag it into Loops.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/step5-2.png)
Your email is now uploaded into Loops and can be sent out!
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/thats-it.png)
# Add a sending avatar
Set up your email sending avatar through third-party platforms like Gmail and Outlook.
Adding an avatar to your emails can improve open rates and brand recall.
![example of email sending avatar](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-a-sending-avatar.png)
## Basic setup
1. Login to the Google Workspace account linked to your Loops sending domain
2. Click the Google logo in the top right corner
3. Click "Add a Profile Picture"
4. Save
For full coverage, add a [Gravatar](https://en.gravatar.com) icon to the email
address.
## Advanced setup
### Adding a sending avatar on a secondary domain
To send email from a secondary domain (e.g., mail.loops.so) with a sending avatar:
1. Log into your Google Admin console with an administrator account
2. Go to "Manage domains" in the dropdown menu
3. Click "Add a domain" and enter the domain name
4. Select "secondary domain" or "User alias domain" as appropriate
5. Add and start verification
Once verified, the secondary domain will use the same sending avatar as the primary domain.
Note that avatars are only visible within the same email client. To display your avatar across all clients, create accounts and upload avatars in each one's settings.
Alternatively, consider using BIMI (Brand Indicators for Message Identification), a new email standard for displaying authenticated logos. BIMI requires some setup and legal work but provides an added layer of trust.
# Insights from Google Postmaster
Gmail doesn't report spam reports to Loops, so setting up Google Postmaster is key to getting an idea of your deliverability performance in Gmail.
Google Postmaster is a free tool that provides users with in-depth data and analytics to help them understand how their emails are performing in Gmail.
This tool provides senders with data on various metrics such as spam rate, domain reputation, email authentication, and delivery errors. By analyzing these metrics, you can identify the issues that may be causing your emails to be marked as spam or not delivered.
You can signup for Google Postmaster here: [https://gmail.com/postmaster/](https://gmail.com/postmaster/)
# Improve your inbox placement
If your emails are not landing in the inbox folder you expect, here are some tips to improve your inbox placement.
Your email deliverability is an ever-evolving metric that can be influenced by a variety of factors.
It's composed of, but not limited to, a combination of the following:
* sending IP
* your domain
* your content
* email clients' history of those
* the content of your current message
* blocklists
* sending frequency
* TLD (Top Level Domain)
Follow these steps to resolve any issues you may be experiencing with your email deliverability. When these steps are followed, we typically see a significant improvement in inbox placement.
## 1. Confirm Domain Record Setup
Ensure your domain records are properly set up is a huge piece of the puzzle. Utilize [Bounce Doctor](https://bounce.doctor) to verify your domain settings if you are not a Loops user. If you already use Loops, you can just visit the [Domain Records](https://app.loops.so/sending-domain) page to see if your records are set up correctly.
## 2. Recent Domain Record Changes
Following on the previous point, if you've added or updated domain records within the last 24 hours, wait for changes to propagate. This is especially important if you've just set up your domain for email sending.
## 3. Don't Send Cold Emails
Avoid sending cold emails from your primary domain or a subdomain linked to it. Use a separate domain dedicated to sales efforts. Any cold emails at all can have a negative impact on your deliverabilty. Talk to your sales team. Please do not send cold emails with Loops.
## 4. Historical Use of Primary Domain for Cold Email
If you have previously used your primary domain for cold emailing, you may need a new domain for sending emails, especially if your domain reputation has had issues in the past. It's not impossible to fix your domain reputation, but it can be a long process. If you're a startup, a fresh domain might be the right choice.
## 5. Send a Welcome Email
[Implement a welcome email with a Loop](/loop-builder) to welcome new users as soon as they join. When a user signs up, they expect a welcome email, so intent is clear and engagement is high. Keeping a steady cadence of emails to all new users will help balance out larger email sends to your entire user base. This is especially important if you're a new sender.
## 6. Content of Emails
Review the content of your emails and refrain from sending emails about crypto, giveaways, financial products or a regulated industry which are typically flagged by email clients. If you need to send these types of emails, review the content and ensure it's compliant with email client policies.
## 7. Use of Popular Top-Level Domains (TLDs)
Consider sending email from a domain with a popular top-level domain (TLD) such as .com or .org. These TLDs are less likely to be flagged as spam by email clients. A few less common TLD's like .io, .ai and .so seem to be fine as well. However brand new TLD's as well as specificially .xyz and .info are often flagged as spam.
## 8. Send Content Your Users Want
Ensure your email content is desirable and relevant to your audience. Focus on valuable updates such as product information rather than unsolicited giveaways or promotions. Would you want to read the email if it came from a service you use? If not, consider changing the content.
## 9. User Consent
Only send emails to users who have explicitly opted in to receive communication from you. Do not email without explicit consent.
## 10. Google Postmaster Tools
Set up [Google Postmaster Tools](/deliverability/gaining-insights) to gain insights into your email performance and identify potential issues.
## Additional Checks: Blocklists and IP Reputation
If you've checked all the above and are still having issues, you may want to check if your IP address is on a blocklist. You can use [MXToolbox](https://mxtoolbox.com/blacklists.aspx) to check if your IP address is on a blocklist. Please note that blocklists change frequently and usually resolve themselves within a few days.
# Maintaining a clean list
A clean list is a happy list. Here’s how to keep your list clean and your emails deliverable.
One of the pillars of good email deliverability is **list hygiene**. Keeping your list clean and up-to-date is a the first step to ensure that your emails are being delivered to the right people.
Most of the emails on your list will likely be legitimate emails, but if you have an in-demand service, users may create temporary email addresses or attempt other methods to gain access to your service and evade limitations you set.
Temporary or fake email addresses are often used once and then abandoned, and can cause your emails to bounce. If you send to too many of these addresses, your deliverability will suffer as the invalid ones will bounce and the valid (but fake) ones will mark your emails as spam.
A few things you can do to keep your list clean:
### 1. Protect the inputs
The easiest way to limit pain is to prevent it from happening in the first place. Start with cutting off the source of the problem by protecting the inputs (your signup forms).
* Use a captcha
* Enable Cloudflare’s bot protection on your site
* Use form validation to ensure that the email address is valid
* Block disposable email addresses
* Use a double opt-in
### 2. Use a service that handles deliverability best practices for you
* Loops automatically handles bounces, unsubscribes, and spam complaints for you
* Just use Loops
### 3. Look for warning signs
* If your open rates are low, it’s likely that you’re sending to a lot of invalid addresses or sending content your subscribers
* If your open rates are high but then drop off, it could be a sign that your emails are being marked as spam or that poor list hygiene is causing your emails to bounce
# Deliverability optimization
How we monitor sends to increase the deliverability of your emails.
During the email sending process, you may see a notification indicating that your email is being monitored for deliverability. This is a proactive measure to ensure that your emails are being delivered to the inbox. A combination of factors are taken into account that may affect deliverability, such as:
* Queuing of emails for delivery
* Email content analysis
* Email sending patterns
* Email sending volume
* Client reputation and email sending history indicators
* Much more!
We have guardrails in place to protect our user's email deliverability (along with yours) and if you see this message, you're seeing one of those guardrails in action.
Emails will be monitored on send to ensure they're hitting the inbox. If you have any questions, contact us via any existing channel or send an email to [support@loops.so](mailto:support@loops.so)
# Subdomains vs root domains
Most email services (including Loops) prefer sending emails from subdomains (hey.company.com) over root domains (company.com).
Subdomains can often be easier to configure and can sometimes be more effective at preventing email from being marked as spam.
It is important to remember that emails sent from a subdomain will also appear in the “from” field of your emails, so make sure to use an address that is recognizable to your audience. We recommend sending from a subdomain like:
* hey.company.com
* mail.company.com
* updates.company.com
Whichever you choose, you can always update it later in your [Domain Settings](https://app.loops.so/settings?page=domain).
# Building your sender reputation
Understanding how to build your sender reputation.
This is a high-level guide, mostly based on our experience as the makers of Loops. We're going to touch on some industry terms and best practices, but ultimately we're focusing on how successful SaaS companies have built their sender reputation using Loops.
You might be reading this guide because you're trying to understand if migrating to Loops and changing your domain is a good idea, if you need to warm up your IP or domain, or if you're just curious about how it all works.
Your sender reputation, as defined by us, is a calculated value based on your domain and your sending IP. This calculation also considers factors like engagement rates, sending volume, and email content quality. We reference this throughout our documentation, and in our support chats, so it's important to understand how it works.
Email clients, such as Gmail, Outlook, and others, also judge sender reputation using largely opaque algorithms. Each factor, such as engagement rates and sending consistency, contributes to whether your email will be successfully delivered.
## Sending Domain
Your domain is the url (e.g., example.com) that you use to send emails. For example, [chris@loops.so](mailto:chris@loops.so) is my personal email address, but we send from [chris@mail.loops.so](mailto:chris@mail.loops.so). Using a subdomain like 'mail.loops.so' is part of our best practice and is also what we would refer to as your sending domain.
A key rule in email sending is that a domain with a strong sending history—consistent volume and high engagement—helps your sender reputation. Conversely, a domain with a weak history can harm it. This can be frustrating when trying to improve your reputation, but if your current sender reputation is good, there’s no need to change your domain.
Changing domains or IP addresses can lead to a reset of your sender reputation, requiring you to rebuild your score from scratch.
This process can be risky and time-consuming, often without significant benefit if your current sender reputation is strong. It’s generally advisable to stick with your existing domain and IP unless you're facing significant deliverability issues.
Other factors can also play a role:
* The volume of emails you send
* The type of content you send
* The users receiving your emails
Beyond that, factors like your subdomain, your domain's age, and even the TLD of the domain matter because they contribute to the perceived trustworthiness of your emails.
## Sending IP
Your IP reputation is largely based on its sending history. If you send from an IP that has a strong sending history, it will help your sender reputation. If you send from an IP that has a weak sending history, it will hurt your sender reputation. Additionally, factors like email frequency, volume, content quality, and recipient engagement play important roles.
If you change either your domain or IP, your sender reputation will need to be rebuilt, which requires following best practices and potentially reducing email volume until a strong reputation is established.
Keep in mind that your sender reputation is made up of both your domain and IP.
## Wrapping Up
Follow the best practices listed in our docs, send relevant content to engaged users, and maintain a consistent sending volume to keep your reputation strong.
If you're starting fresh, consider using a subdomain for sending emails and keep your sending volume conservative initially.
For any questions, just ping [chris@loops.so](mailto:chris@loops.so).
# Sending to large audiences
Tips for sending emails to a large group of new contacts.
Most users in this scenario face two key challenges:
* You have a large audience that you haven't contacted before or rarely have in the past.
* Your domain has little to no sending history.
As a result:
* Users are not expecting emails from you, as they haven't received any in the past.
* Email clients (Gmail, Outlook, etc.) don't recognize you, so your sender reputation is nonexistent.
It’s **really important** to handle this well, so follow these steps or contact [chris@loops.so](mailto:chris@loops.so) with any questions.
### "Warming Up" Your List
We want to build your sender reputation **and** start emailing your best users at the same time. Thankfully, this is easier than it sounds.
The easiest way to do this is *not* by contacting your existing list but by contacting users that are just joining your platform for the first time. Why? Because in our experience, as individuals and as the makers of Loops, the most likely time a user will engage with your emails is when they first join your platform.
### Setting Up an Onboarding Loop
So how do we start emailing these new users?
Start by [setting up a Loop](https://loops.so/docs/loop-builder#building-a-loop) that greets users as soon as they join your platform.
These users are the most active and are most likely to respond favorably, positively impacting your business and your sender reputation.
You should let this Loop run for a few days while your sender reputation is built up and you have a chance to understand how your users react to the type of emails you're sending.
Ideally, open rates will now be >40% at this point for the first email in your Loop.
### Engaging Your Most Active Users
After your onboarding Loop has run for a few days, you can begin to backfill your audience in Loops by importing a CSV of your existing users or by using our API.
While you can (and probably should) import all existing users at this point, we recommend contacting users that signed up over the last seven days prior to the start of the Loop we set up.
Depending on audience size, you could also import users from up to three months ago, but our goal here is to make sure we are contacting users that still engage with your platform.
Alternatively, instead of importing users by the creation date of their account, you can do it by their last login date if you have that information stored.
If you don't have the information stored, you could start now and import users in a week or two after you have an idea of who your most engaged users are.
### General Recommendation for Importing Contacts
A general recommendation would be to import any contacts who have logged in within the last 90 days and then also set up a Loop to welcome all new users going forward. Then you get transactional sending to any contacts in your audience free of charge as well.
### Expanding to Older Users
After your most engaged users have been contacted and your Loop has continued to send, you should have a good idea of how your users are responding to emails that you send them.
You can then begin to expand your audience and import some older users. We recommend sending in batches to limit any potential issues with the domain reputation.
If you notice your open rates dipping below average at any point, it’s a good indication that you’ve reached as far back into your audience as you’ll want to go. At that point, it’s a good idea to only contact users that were previously on your list if they reengage on your platform with a login.
### Wrapping Up
By following these steps, you should be able to successfully send emails to your user base without damaging your domain reputation. Remember to always monitor your open rates and engagement levels and adjust your email strategy accordingly.
For any questions, just ping [chris@loops.so](mailto:chris@loops.so).
# Email open rates
Understand how open rates can be affected by clients and networks.
Have you ever sent out an email campaign and noticed that some of the recipients showed as "opened" nearly instantly upon sending, while others took a while or didn't show at all? This discrepancy can be confusing and make it difficult to interpret your email open rates accurately.
If your contacts are using Apple Mail or are behind corporate firewalls, it's likely that your open rates are being affected by email privacy measures. Here's what you need to know.
## Apple Mail
Apple Mail Privacy Protection: Apple Mail is a popular email client that is used by millions of people worldwide. In an effort to protect user privacy, Apple introduced Mail Privacy Protection with the release of iOS 15, iPadOS 15, and macOS Monterey. This feature blocks email tracking pixels, obscuring email open rates, and making it difficult to know exactly when an email has been opened.
If your recipient is using Apple Mail to access their Gmail or other email provider's inbox, then their email will be proxied through Apple's servers, which will affect your open rates.
## Corporate firewalls
Many companies use firewalls to protect their network and prevent unauthorized access to their data.
These firewalls can also affect email open rates by blocking or caching tracking pixels, which are used to track when an email is opened. If your recipient is behind a corporate firewall, then their email client may not be able to download the tracking pixel, which will affect your open rates. If they cache the pixel, it may show as opened immediately.
So, what can you do to get a better understanding of your email open rates? Here are a few tips:
1. **Use other metrics:** While open rates can be a useful metric for measuring the success of an email campaign, they're not the only metric you should be using. Click-through rates, conversion rates, and revenue generated are all important metrics that can give you a better understanding of how your email campaign is performing.
2. **Use a different tracking method:** If you want to track email opens more accurately, you can use a different tracking method that doesn't rely on tracking pixels. For example, you could use a unique link in your email that redirects to your website. By tracking the number of clicks on that link, you can get a better understanding of how many people opened your email.
Open rates are just one metric among many that you should be using to measure the success of your email campaign. By using other metrics, segmenting your audience, and using different tracking methods, you can get a more accurate picture of how your email campaign is performing.
# Events
Events let you trigger emails when something happens in an external platform.
## About events
Events represent a payload of data that can be used to trigger emails. They can be sent to Loops with [the API](/api-reference/send-event) or via [an integration](/integrations).
Events are used to trigger emails in a [loop](/loop-builder) and can contain [personalized data](/events/properties) for each email.
## Creating events
Events can be created automatically or manually in several ways. As well as specifying a name, you can also create [event properties](/events/properties) with each of these methods.
### Automatically by sending an event
You can create an event by sending an event with a new event name.
For example, `creditWarning` here is a new event. This request will create a new event in your account.
```json
{
"email": "chris@loops.so",
"eventName": "creditWarning",
"eventsProperties": {
"creditsPurchased": 1000,
"creditsUsed": 903,
"accountName": "Loops"
}
}
```
### Manually from the Events page
Navigate to the [Events page](https://app.loops.so/settings?page=events) to create an event manually.
![Add an event from Settings](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-event-settings.png)
### Manually from an Event trigger node
When [building a loop](/loop-builder), use the **Event received** trigger node to create an event (see below).
## Specifying an event for a Loop
You can use events to trigger email sending within loops.
When creating or editing a loop, select **Event received** in the "Trigger Type" dropdown.
Type in the name of a new event or start typing the name of an existing event, then select from the dropdown.
![Add an event from the Loop builder](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-event-loop.png)
## Sending events
Now you have events set up in your Loops account, you can start sending events using the API or integrations.
### Sending events with the API
Using the API, send events to the [Send event endpoint](/api-reference/send-event):
```
POST https://app.loops.so/api/v1/events/send
```
All that's required is an `email` or `userId` to identify the contact, plus the `eventName`.
```json
{
"email": "sam@loops.so",
"eventName": "planUpgrade"
}
```
The `eventName` can either be an existing event in your account or a new event name.
If a contact is not found with the provided `email` or `userId`, a new contact will be created.
You can include [contact properties](/contacts/properties) in the request, which will be saved onto the contact. These contact properties can be used in emails to your contacts or for [filtering and segmenting your audience](/contacts/filters-segments).
```json
{
"email": "sam@loops.so",
"eventName": "planUpgrade",
"firstName": "Sam",
"favoriteColor": "red"
}
```
To provide your emails with event-specific data, include event properties in the request. [Read more about event properties](/events/properties)
```json
{
"email": "sam@loops.so",
"eventName": "planUpgrade",
"firstName": "Sam",
"favoriteColor": "red",
"eventProperties": {
"newPlan": "Pro",
"oldPlan": "Basic",
"planPrice": 29,
"isLifetime": false,
"updateDate": "2024-03-07T10:09:23Z"
}
}
```
### Sending events via an integration
Many of [our integrations](/integrations#send-email) also support sending events, giving you options to send events without building with our API.
## Viewing and editing events
In your Loops Settings the [Events page](https://app.loops.so/settings?page=events) shows the list of your different events, including how many times they've been sent. Counts are updated hourly.
![Events page](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/events-page.png)
To edit event properties, click on an event. (You can also edit events by selecting "Edit properties" in the Loop builder's event trigger popup.)
![Editing an event](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/edit-event.png)
Events cannot be deleted.
Below the list of events, you can see the event stream for your account. This includes events sent to us [via the API](/api-reference/send-event) and any of [our integrations](/integrations).
![Event stream](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/events-stream.png)
You can sort your events either by email, period of time or event name. You can even create complex segments to view events through a period of time by a single user.
## Testing events
You can test events by sending to email addresses with `@example.com` and `@test.com` domains (for example `user1@example.com` and `user2@example.com`).
Events will fire as normal but emails will not be sent to `@example.com` or `@test.com` email addresses, making this a good way to test how events are working in your account without affecting your sending domain’s reputation.
# Event properties
Learn how to use event properties to personalize your emails.
You can include additional data for each event with event properties, which can be used to include personalized information in emails triggered by your events.
Once included in an event, event properties can be added to emails within your loops.
## Adding event properties
You can add event properties for your events from two places.
### Events page
Firstly, you can add them from the [Events page](https://app.loops.so/settings?page=events). Click on an event and then **+ Add event property**.
![Adding an event property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-event-property.png)
### Loop builder
Secondly, you add event properties from an **Event received** node in the loop builder by clicking on the **Edit event properties** button.
![Adding an event property in the loop builder](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-event-property-loop.png)
### Important information about event properties
* Event properties must have unique names within the same event.
* Empty spaces are trimmed from the beginning and end of property names.
* Event properties can be one of four types:
* String
* Number
* Boolean
* Date
* Date values can be either a Unix timestamp (*in milliseconds*) or an [ECMA-262 date-time string](https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format), similar to contact properties. [Read more](/contacts/properties#dates)
## Editing event properties
You can add, rename, delete, and change data types for event properties in the event editor popup (either from the [Events page](https://app.loops.so/settings?page=events) or within the loop builder, as above).
![Editing an event](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/edit-event.png)
## Sending event properties in an event
You can add event properties to your [Send event](/api-reference/send-event) API request using `eventProperties`:
```json
{
"email": "sam@loops.so",
"eventName": "planChange",
"firstName": "Sam",
"favoriteColor": "red",
"eventProperties": {
"newPlan": "Pro",
"oldPlan": "Basic",
"planPrice": 29,
"isLifetime": false,
"updateDate": "2024-03-07T10:09:23Z"
}
}
```
Conversion attempts are made for mismatched types (e.g. if you send a string for a number property).
New properties not previously defined for an existing event will not be
available when sending emails. Make sure you add event properties in Loops
before including them in your event requests. If you send a request with a new
`eventName` we will create a new event in your account and include the
properties listed in `eventProperties`.
## Using event properties in emails
Event properties you create become available in emails once Loops has received events containing them.
Click on the Event properties icon `⚡️` in the editor toolbar (only available in emails within your loops) and select the property you want to add.
![Add an event property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/event-property-icon.png)
{/* Unlike contact properties, fallbacks for event properties are optional. Missing a fallback prints that the property doesn't have one. */}
# Custom form
Integrate with Loops via a form endpoint, which will work with any type of custom form solution you have set up.
Our form endpoint lets you add new contacts to your audience from an HTML form or using JavaScript.
## Find the form endpoint
To submit data to Loops you will need to retreive the form endpoint URL that's linked to your Loops account.
1. Go to the [Forms page](https://app.loops.so/forms) in your Loops account.
2. Click on the **Settings** tab.
3. Copy the URL shown in the **Form Endpoint** field.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/form-endpoint.png)
## Create a form
In a form, add `input` elements for each of the contact properties you want to collect.
You can add fields for any of the [default contact properties](/contacts/properties#default-contact-properties) plus any of your custom properties.
For each form field use the "API Name" value found from your [API settings page](https://app.loops.so/settings?page=api) as the `name` attribute.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/contact-properties-table.png)
Here's a simple example form that collects name, email address and assigns a custom user group:
```HTML
```
To add subscribers to mailing lists, include a hidden field called `mailingLists`. You can use a single mailing list ID or to add subscribers to multiple lists, use a comma-separated list of mailing list IDs.
Make sure that any mailing list you add to a form is [Public](/contacts/mailing-lists#list-visibility). You cannot subscribe contacts to private mailing lists from the form endpoint.
```HTML
```
If you need a hand integrating with your custom form, just shoot [adam@loops.so](mailto:adam@loops.so)
an email and we'll help you integrate with anything your specific setup ✌️
## Submit with JavaScript
If you would rather submit a form using JavaScript, you can make a `POST` request to your form endpoint.
Make sure to set the `Content-Type` header to `application/x-www-form-urlencoded`.
```javascript
function handleSubmit() {
const formBody = `firstName=${encodeURIComponent(firstName)}&email=${encodeURIComponent(email)}&mailingLists=${encodeURIComponent(mailingListIds)}`;
// Change this URL to your own endpoint URL
fetch("https://app.loops.so/api/newsletter-form/YOUR_FORM_ENDPOINT", {
method: "POST",
body: formBody,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
}
```
Responses from this form endpoint will be one of the following:
```json
HTTP 200
{
success: true
}
```
```json
HTTP 400 or 500
{
success: false,
message: "A descriptive error message."
}
```
This endpoint is rate limited. If you go over the limit, will see a `HTTP 429` error just like with the API. [Read more about how to handle 429 responses](/api-reference/intro#rate-limiting)
## FAQ
We rate limit requests from the same IP to once per minute and also do not
allow duplicates of the same email address. It's likely the error is related
to one of these cases.
# Simple form
Collect signups from any web page with a customizable form.
Check out our specific documentation for adding forms to
[Framer](/integrations/framer) and [Webflow](/integrations/webflow).
You may want to collect signups from your website directly into Loops.
## Generate the form
Easily generate an HTML or JSX form for collecting new signups for your mailing list from inside Loops.
Go to the [Forms page](https://app.loops.so/forms), customize your form (such as mailing list, layout, button color and success message) and copy the HTML into your website.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/simple-form.png)
## Add more fields to the form
It's possible to add other fields to your form if you want to collect more than just email addresses.
When adding new fields, use the "API Name" value found from your [API settings page](https://app.loops.so/settings?page=api) as the `name` attribute for each field.
For example, this field would collect a First Name:
```html
```
If you want more flexibility when creating signup forms, [read about creating custom forms](/forms/custom-form).
# Sending emails to Apple “Hide my email” addresses
Apple has recently begun offering their iCloud+ users more and more privacy options when it comes to how they move and appear on the internet.
What does this mean for email? It turns out… quite a bit.
When it comes to email deliverability, [Hide My Email](https://support.apple.com/guide/icloud/set-up-hide-my-email-mm9d9012c9e8/icloud) provides Apple users the opportunity to create unique, random email addresses that forward to their actual email address. This allows them to keep their real email address hidden from online services and email marketers (likely, you).
This can pose challenges for businesses and marketers that hope to track user engagement or maintain an updated and engaged email list.
## Sending emails to customers using Hide My Email
Sending emails to customers that are using Apple’s Hide My Email feature can result in hard bounces — meaning your email will not be delivered.
If you’re using [Loops](https://loops.so/) as your ESP (email service provider) to send your marketing and transactional emails, an additional step is needed to ensure these members of your audience remain in the loop (pun intended).
It’s simple.
You will need to register your sending domain with Apple through these quick steps.
1. Login to the Apple Developer Console
2. Click **Services** under the category labeled Certificates, Identifiers & Profiles
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/ePMohygJlAarcRmFAv6GtcE9w.webp)
3. Click **Configure**
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/Gr2ItNdb8mCINSZHpBbHOoPhqs.webp)
4. Click the `+` icon under Email Sources
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/WGNTKDV9jsOJ1euiPgzoptQsfk.webp)
5. Verify SPF and Send Test
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/du5rsZ3IXp1Tec0HRJc5vsxL8.webp)
You'll want to register the email address that we provide for you in-app as well as the usual domain.
For example: `envelope.yourdomain.com` (envelope is the part we are generating for you) and `yourdomain.com`.
That’s it! Goodbye hard bounces and hello inbox.
## What if I don’t do this?
If you don’t register your sending domain with Apple prior to sending emails it may very likely result in a hard bounce (email will not be delivered to the intended recipient).
If you are using Loops and notice hard bounces to these email addresses in your campaign metrics please follow the above steps to register your domain.
Once your domain is registered, reach out to us and we can manually remove the emails from our block list.
# Bubble API Connector
Send data to Loops from Bubble using the API Connector plugin.
This guide helps you set up an API connection to Loops from your Bubble app.
In this example, we will create an integration that allows you to sync Bubble users to your Loops audience.
We have created an [official plugin for Bubble](/integrations/bubble), which contains actions for all Loops API calls. However, it is limited to what it can do by how Bubble works.\
THis tutorial helps if you need more control or flexibility over the data that is sent to Loops.
## Install the API Connector plugin
In Bubble, you need to first install the API Connector Plugin. This plugin is what makes the API calls to Loops.
Go to Plugins and click **+ Add plugins**.
Search for "API Connector" and click **Install**.
![Search for API Connector](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-search-plugin.png)
## Add a Loops API connection
Now you have the plugin installed, you can add an API connection.
Click **Add another API**. In the form that appears, enter "Loops" into the **API Name** field (Bubble uses this field to group API calls together in the interface).
Make sure the **Key name** value is "Authorization" (this is the default).
In the **Authentication** field, select "Private key in header".
In Loops, go to your [API Settings page](https://app.loops.so/settings?page=api) and copy an API key (you can create a new key if you like).
Back in Bubble, in the **Key value** field, write the word `Bearer`, then a space character, then paste your API key, so it looks something like `Bearer YourApiKey`.
![Add the Loops API](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-connect-api.png)
## Add an API call to sync users to Loops
Now you can create an API call using the connection you just created. Click **Add another call** at the bottom of the gray box.
In the **Name** field, write something like "Sync users".
In the **Use as** field, select "Action". The **Data type** field should be "JSON" (this is the default).
In the dropdown where it says "GET", select "POST", and in the subsequent field, paste the following endpoint URL:
```
https://app.loops.so/api/v1/contacts/update
```
![Add an API call](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-add-api-call.png)
Now all that's left is to set up the request body, which is the data that's sent to Loops. This will depend on what kind of data points you want to send.
In this example, we will add a [custom contact property](/contacts/properties) called "Plan name" (which we [already added in Loops](/contacts/properties#add-a-property)).
Due to how Bubble handles empty values, make sure to only add properties to this request body that will always contain a value. Otherwise, Bubble will send `"null"` as the value instead of an empty value, which will mean, for example, your contact's first name will become `null`.
To make the request, we have to include an email address (which is required to create new contacts in Loops). Then we'll also add a "User ID" value (which will maintain a distinct connection between a user in Bubble to their contact record in Loops) plus the "Plan name" property. Due to the data in my example application, I know all three of these fields will always have a value.
In the **Body** field, paste this:
```json
{
"email": "",
"userId": "",
"planName": ""
}
```
If you then click anywhere outside the **Body** field, you'll see two sets of fields appear below it, one for each of the three custom variables (`Email`, `User_ID` and `Plan_name`) we added to the body data.
Uncheck the **Private** checkbox for each of these variables, otherwise they won't show up in the Bubble interface when you come to use this API call.
![Adding body data](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-body-data.png)
The final step is to initialize the call, which will show Bubble that the API call works.
To do this, enter some example values in each of the **Value** fields, then click **Initialize call** (this will send real data to Loops).
If it works, you'll see a success message and a confirmation of the returned values from Loops. Click **Save** to complete setting up the API call.
![Request success](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-success.png)
If the request is not successful, you should see a message telling you what went wrong.
When you're done, remember to delete the test data you just added in the **Value** fields.
## Add the action to your Workflow
The final step is using your API call inside your application.
To do this, go to **Workflows** in your Bubble account and create a workflow for when you want to send a user to Loops.
In this example, I want to sync users to Loops whenever they log in (they could also be synced after other events, like if their email address changes).
To do this, click **Click here to add an event...** and select "General > User is logged in".
Click **Click here to add an action...**, hover over **Plugins** and select the action you created by the name you gave it (naming is organized by "API name - API call name").
![Select the API call](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-select-call.png)
This will show a popover containing the fields you added in the previous step, allowing you to insert your data in Bubble into the API call.
Click into a field and then **Insert dynamic data**, then select the data you want to send to Loops. (In my example I searched for "Current User" and then selected `'s email`, `'s unique ID` and `'s plan` to fill out the three fields.)
![Add data to API call](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-add-data.png)
Now when the selected event happens, Bubble will make an API call to Loops!
To verify everything is set up correctly, log in to your Bubble app (to trigger the event) and then check the [Audience page](https://app.loops.so/audience) in Loops to see if your user account appears.
## Other examples
There are lots of different ways you can use Bubble's API Connector to send data to Loops:
* Create a newsletter subscription form and send all submitted email addresses to Loops.
* Sync contacts whenever a user's email address is changed in Bubble.
* [Trigger an event](/events) in Loops for all new sign ups using the [Send event endpoint](/api-reference/send-event), to enter new users into a welcome email sequence.
* Periodically sync [contact properties](/contacts/properties) to Loops so you can send personalized emails.
## Learn more
}
href="/integrations/bubble"
>
Manage contacts and send emails with our Bubble plugin.
View all of our API endpoints.
Learn more about custom contact properties.
# Set up a welcome email sequence for new Ghost members
Send automated email sequences to new Ghost subscribers using Zapier and Loops.
This guide helps you set up email sequences that get sent to all new subscribers to your Ghost site.
With Loops, you can set up sophisticated sequences called "[loops](/loop-builder)", allowing you to send a range of welcome emails to your members over a period of time.
Using [Zapier](https://zapier.com), we can automatically add every new member who signs up on your Ghost site to your Loops audience.
## Set up the Zapier Trigger
The first step is to connect your Ghost site to Loops using Zapier.
Sign up to Zapier and create a new Zap using Ghost's **Member Created** Trigger.
![Add Ghost trigger](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/zapier-ghost-trigger.png)
This creates an automation that will trigger every time a new member is created in Ghost. Zapier will then send the contact's information over to Loops.
Now connect Ghost from the Trigger by clicking **Account** then **Sign in** and then pasting in your Ghost API key and API URL. To find these, go to Settings in your Ghost admin, search for "Integrations" and click on **Zapier**.
![Sign in to Ghost](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/zapier-sign-in-ghost.png)
## Set up the Zapier Action
Next you need to link up Loops as the Action. Click the **Action** node, search for Loops and select the **Send Event** option in the Event dropdown.
Click **Continue**, then **Sign in** and paste in your Loops API key (which you can find from your [API Settings page](https://app.loops.so/settings?page=api)).
![Sign in to Loops](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/zapier-sign-in-loops.png)
Instead of using an event for the loop trigger, you could also choose to send the loop to every new contact created in your audience.\
We choose the event trigger in this example as you may add other contacts to your audience from other sources than Ghost.
Now click **Continue** to move to the **Action** tab. This is where you can configure which Ghost data is sent to Loops.
As you click each field, you can select the different Ghost-provided data.
In **Email**, select the Email field. In **User ID**, select the ID field.
In the **Event Name** field, write something like `newMember`. This is the name we'll use in Loops to trigger the email sequence. You can use any name, but make it descriptive. You'll need this name in the next step inside Loops.
![Adding an event name](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/zapier-ghost-email.png)
If you want to include contact-related information in your emails you can use [event properties](/events/properties). To do this, add more Ghost data in the **Event Properties** field. For example, if you want to include the user's name, subscribed status, member status or your newsletter's name, you can add these properties here. Click the `+` button to add new properties each time.
![Adding event properties](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/zapier-ghost-properties.png)
Click **Continue** to see an overview of the event and its data that you'll send to Loops. Here you can test the action works by clicking **Test Step**. This will send actual data to Loops, which you will see in the Event Log section on the [Events page](https://app.loops.so/settings?page=events).
When you're happy everything is set up properly, click **Publish**.
If you ever change the event properties sent from Zapier, you need to update the event data in Loops to match. You can do this from [Settings -> Events](https://app.loops.so/settings?page=events). Click on the event and edit the listed properties. [More info](/events/properties#editing-event-properties)
## Create an email sequence
Now that the connections are set up, you can create the email sequence "loop" in Loops.
Go to Loops and click on **Loops** in the sidebar.
Click **New**, which will create a new loop and show the [loop builder](/loop-builder).
Select the **Event is fired** trigger option.
Click on the **Event received** trigger in the loop builder and enter the name you entered in Zapier in the previous step (in this example, `newMember`).
![Select the event trigger](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/member-trigger.png)
You can edit the **Timer** node if you want to add a delay between the event being received by Loops and the email being sent to your Ghost members.
![Set a timer delay](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/timer-3-days.png)
You can also add a filter to the audience for this loop, if you want to limit sending to a certain sub-group of your members. If you want the loop to send to all new Ghost members, just leave it as "All contacts".
Lastly, click the **Send email** node and then **Create email**. You'll see the [email editor](/creating-emails/editor) open, where you can create your email.
If you opted to send event properties from Zapier, you can add them to your email by clicking the `⚡️` button in the editor toolbar.
![Insert event property](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/add-event-properties.png)
Once your first email is complete, you can add more Timer and Email nodes to your loop to complete your email sequence. Just click on the `+` icon between nodes to add new ones.
## Learn more
Read more about triggering emails with events.
Learn how to create stylized emails and add personalization.
}
href="/integrations/zapier"
>
Manage contacts and send emails from thousands of other platforms.
# Guides
## Deliverability
Improve your email deliverability with these guides.
## Integrations
How-to guides for connecting Loops to other platforms.
}
href="/guides/bubble-api-connector"
/>
}
href="nextjs"
/>
## Creating emails
How to create different kinds of emails in Loops.
## Email basics
Learn more about email.
## Docs blog
* [How we create our documentation](/guides/how-we-work-documentation)
# How to set up customer lifecycle emails in Loops
How to send onboarding, dunning and churn emails to your customers with Loops.
For SaaS companies, there are a few important events in a customer lifecycle that email can help with.
* **Acquisition emails** are emails sent after a user signs up for a waitlist, platform or newsletter.
* **Onboarding emails** help brand new users get familiar with—and get the most out of—your product.
* **Retention emails** keep your users engaged long-term.
* **Re-engagement emails** attempt to get users active again if they haven't used your platform recently.
* **Dunning emails** help reduce churn by prompting the user to re-activate a subscription or fix payment issues.
* **Re-activation emails** attempt to bring users back after a cancelation.
With Loops, you can easily set up "loops" (email workflows) plus our API (or an integration) to help with each of these use cases.
## How it works
To get this set up in Loops, the idea is to create a [loop](/loop-builder) for each of the types of email you want to send. So there would be a loop for activation emails and a loop for dunning emails and so on.
A loop is like an email sequence containing emails, time delays, audience filters and an initial trigger.
We will use a [custom contact property](/contacts/properties) called `subscriptionStatus` to enter users into each of the loops at different times in their subscriptions.
This property is used as the [loop trigger](/loop-builder/loop-triggers); if the property is ever changed—using [an integration](/integrations) or the [Loops API](/api-reference)—we trigger a loop, which will send emails to the contact.
## Add a contact property
First, let's add the contact property to the audience in Loops.
Go to your [Audience page](https://app.loops.so/audience). Click on a table header to show the dropdown then select **Add property**.
Enter "Subscription status" into the **Name** field and make sure **String** is selected in the "Type" field. (You'll notice that the "stored name" of your property is `subscriptionStatus`. This is the name we'll use in the API and integrations).
Click **Add Property** when you're done. Your new property was added to the far right of the Audience table.
## Update contacts
Now you can click on contacts and update the value manually one-by-one, or use the API or an integration to update contacts programmatically.
To update contacts in bulk you can download your Audience as a CSV, update values and [re-upload the file](/add-users/csv-upload).
## Create loops
The next step is to create the loops, one for each type of email. Repeat the following step for each of the different subscription statuses you want to send emails for.
Go to the [Loops page](https://app.loops.so/loops) in your account and click **New**.
Select the **Contact update** option, which will create a new loop using that trigger.
![Select trigger](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/triggers.png)
You will enter the [loop builder](/loop-builder). Click on the **Contact updated** node to set up the loop trigger.
### Set up the trigger
1. Select the "Subscription Status" property from the **When** dropdown.
2. The **Changes from** dropdown should have "Any value" selected.
3. Netx you need to specify wheat value Loops should look out for to enter users into the loop.
For example, for onboarding emails, you can choose "is empty" from the **To** dropdown. For re-activation emails select "Equals" from the **To** dropdown and enter a relevant value like "Canceled".
4. **Trigger time** should be set to "Every time"; this will make sure users are entered into the loop every time that the Subscription Status value matches.
### Create emails
Now create the email(s) you want to send from each loop.
You can add as many emails as you like into each loop, separated with timers. If you want to send emails to certain groups of contacts, you can use Audience filters in your loop.
We have a range of [email templates](https://app.loops.so/templates) available, which you can use as a base for all of your subscription emails.
![Templates](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/getting-started.png)
If you want to use cohesive branding in your emails, make use of [Saved styles](/creating-emails/editor#saved-styles) in the editor.
![Saved styles](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/message-visual.png)
## Update the Subscription status value
The final step is to make sure that your contacts have the correct "Subscription status" value assigned to them in Loops.
This will make sure they are in the correct loops at the correct moment within their subscription.
Using the API you can make a simple `PUT` call to the [Update contact endpoint](/api-reference/update-contact), with a request containing the contact's email address and subscription status.
(You can also add more contact properties in this call if you want to add more data to the contact in Loops.)
Using the Update contact endpoint will either create or update a contact in
Loops using the provided email address.
```json
{
"email": "canceleduser@gmail.com",
"subscriptionStatus": "Canceled"
}
```
Many of [our integrations](/integrations) allow syncing of contact data. Just make sure you create or update contacts and include the current `subscriptionStatus` value.
Now you have set up different loops to trigger when the "Subscription status" value changes, your users will be automatically entered into each loop and receive the correct emails at the correct times during their subscription lifecycle.
## Example loops
Here are some example loops you can create along with a suggested trigger and loop contents.
### Onboarding
Sent to brand new users.
* **Trigger**: Contact added or Contact updated (e.g. `subscriptionStatus` is empty).
* **Audience filter**: Match the trigger (e.g. `subscriptionStatus` is empty).
* **Loop contents**: 1–5 welcome and onboarding emails over the first 30 days.
### New subscribers
Sent to users who just started paying.
* **Trigger**: Contact updated (e.g. `subscriptionStatus` changes to "Paying").
* **Audience filter**: Match the trigger (e.g. `subscriptionStatus` equals "Paying").
* **Loop contents**: 1–3 emails about paid-only features over the next 3 days.
### Dunning
Sent to customers who had a first failed payment.
* **Trigger**: Contact updated (e.g. `subscriptionStatus` changes to "Failed").
* **Audience filter**: Match the trigger (e.g. `subscriptionStatus` equals "Failed").
* **Loop contents**: 1–3 emails during your dunning period.
### Churn
Sent to customers who have just cancelled their payments.
* **Trigger**: Contact updated (e.g. `subscriptionStatus` changes to "Canceled")
* **Audience filter**: Match the trigger (e.g. `subscriptionStatus` equals "Canceled").
* **Loop contents**: 1 email saying goodbye and asking for feedback.
# Open rates are a vanity metric
And why that’s okay.
When it comes to email marketing, there are countless metrics that you can track. Some of these metrics may be fun to track and look great on paper (your computer screen) but unfortunately don’t actually lead to improved business results.
These are vanity metrics.
While you might think that vanity metrics help paint a picture of success or improvements to unknowing stakeholders, they are ultimately a distraction.
Facebook likes, Twitter followers, blog pageviews… these are all vanity metrics because they don’t materially impact the success of your business in a tangible way.
But so are email open rates.
Yes, you read that right. The main metric you’ve been tracking (and sharing) to gauge the success or failure of your email marketing campaigns is (mostly) just for show.
## What is an email open rate?
An email open rate is the number of unique opens your email campaign receives. Calculating open rate is simple:
Number of unique email opens / Number of delivered emails x 100 = Open Rate
Delivered emails are important here because hard bounced emails do not count towards this calculation.
Note: a hard bounced email is an email that cannot be delivered due to an unchanging and permanent reason. Unfortunately, there is nothing that you can do to reverse this to force your email through.
Some common reasons for a hard bounce are recipient email address doesn’t actually exist, recipient mail server doesn’t exist, and invalid domain name. While a hard bounce will prevent your email from arriving in its intended inbox it is possible that a hard bounce could be caused by something as simple as your recipient having a typo in their email address.
To keep things simple, let’s assume you sent and delivered an email to 100 different users in your campaign. 23 of your users opened this email giving you an open rate of 23%.
23 / 100 = .23 x 100
Easy enough, right?
Up until recently, open rates were a universally loved way to gauge campaign performance.
So what changed?
## Your open rate is (now) a vanity metric
Apple changed — mostly. With a dominating [59.8% email client market share](https://www.litmus.com/blog/email-client-market-share-february-2022/), any change they make is a huge deal.
New privacy initiatives from many of the largest email clients are quietly removing email senders ability to successfully track open rates.
Apple is leading the charge with their new “Mail Privacy Protection” (first introduced in 2021 with iOS 15) that allows users to opt-in to having Apple pre-load their email upon receipt. By doing so, the email’s tracking pixel will immediately trigger.
Note: an email tracking pixel is a 1px by 1px square image that is inserted into an email and is transparent in color and invisible to the recipient. These tracking pixels are what allow marketers to measure open rate, click rate, traffic sources and more.
This change artificially inflates open rates as delivered emails will now automatically show as opened whether they truly have or have not been opened by the intended recipient.
These changes to email open tracking are completely out of the sender’s control.
And to top it all off, these changes affect not only users receiving emails on the Apple Mail app itself but also those who use an Apple client in any way (r[egardless of email server](https://www.litmus.com/blog/apple-mail-privacy-protection-for-marketers/)). This means that using GMail, Yahoo, Outlook, etc. on iOS 15 may also contribute to your now-inflated open rate.
What was once a key metric to track and share with key stakeholders should now be viewed with a bit more skepticism.
## What’s next?
It is highly unlikely that these recent privacy changes will be reversed anytime soon (ever).
So what can you do about it?
The answer may surprise you.
We suggest continuing to run your campaigns as you have been.
Continue to send consistent emails (both in frequency and content), create intriguing and accurate subject lines and body content, segment your list so that only the most relevant audience is receiving your emails, and pay close attention to your unsubscribe rate.
However, now you should put a greater emphasis on tracking specific product goals in relation to your email campaigns. Have actionable metrics in mind – metrics around business goals such as generating free trials, converting trials to paid, increased usage of your app or inviting team members.
And actually, this should have been the goal all along.
High open rates don’t necessarily lead to increased sales or profits for your business, the end result of those opens is what really makes the difference.
Now that your focus has transitioned to more tangible KPI’s that lead to specific product goals being met it will be much easier to accurately measure the success of your email marketing campaigns.
Looking back on it, maybe your email open rate becoming a vanity metric overnight will ultimately be a blessing in disguise.
Take this as an opportunity to refocus your attention on the KPI’s that ultimately matter for your business. High open rates may have been impressive in the past but now it’s time to craft and measure your email campaigns against the things that truly move the needle.
# Product updates
Our updated, definitive guide for sending product updates.
## Introduction
A product update should be sent once a month with updates about what you shipped recently. This typically includes new features, improvements, and bug fixes.
Things to keep in mind:
* Brevity is key. Users don't want to read a novel.
* If you send valuable content, users will come to expect (and open) it.
* It's okay to send multiple emails in a month if that's your shipping cadence.
Learn more tips for crafting effective emails and improving open rates.
## How to craft a product update email:
1. [Create a new email Campaign](/creating-emails/editor)
2. Add your logo at the top of the email, [save it as a component](/creating-emails/components) if you haven't already.
3. Add a simple subject line, like "The latest updates from Loops"
4. Add a simple intro paragraph, with a link to the full changelog, potentially socials and a highlight of the most important changes along with a call to action to read the full email.
5. Try to limit the number of updates to 2-3, and make sure they are relevant to the content. It's better to have a single or a couple impactful, relevant updates than a long list of updates that are not relevant to the user.
6. In the footer, add a link to the full changelog, socials, and a link to unsubscribe.
7. [Send the email!](/creating-emails/sending-first-email)
Be careful not to overwhelm your users with too many updates. Focus on the
most impactful changes.
## Choosing your audience
### For new senders
If you're just starting out, send to all users and maintain a steady cadence over time.
### For established senders
If you have an existing list but haven't sent product updates before:
* Send to active users who have engaged with your product in the last 30 days
* Include users who have created an account in the last 30 days
* If the audience size is less than 5,000 users, send to all users
Learn how to create targeted segments for your product updates.
Learn how to create and send your first email in Loops.
Add dynamic content to make your product updates more relevant.
Create reusable elements for consistent product update emails.
Explore different types of emails you can send with Loops.
# How to create a scheduled email with Loops
How to send a daily, weekly or monthly email with a summary of what's happened in your app.
This email type may also be referred to as a "rollup" email or a "summary" email. The idea is to send a single email that summarizes what's happened in your app over a period of time.
These kinds of digest emails are a great way to keep your users engaged with your app.
The best way to do it today is a Loop with an [event trigger](https://loops.so/docs/loop-builder/loop-triggers) set to fire “every time” with an event payload containing the updated property you’d like to send.
Then at the end of the day, week or month you can trigger a digest email with a summary of the events that happened.
## Create the loop and event
Go to the [Loops](https://app.loops.so/loops) page and create a new loop.
Choose the **Event is fired** trigger. You will enter the loop editor.
Click on the **Event received** node and type the name of your event. You can re-use an existing event or create a new one from this input.
For example, you can use a name like `sendDigest` and then click **+ Create new event**.
![Creating a trigger node](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/scheduled-trigger.png)
Next, click on the **Edit event properties** button to add [properties](/events/properties) to your event. Properties are extra pieces of data that you can attach to each event. This data is then made available in every email you send.
In the event editor overlay, click **+ Add event property** and add any properties you want to include in your digest email.
![Adding event properties](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/scheduled-event-properties.png)
Make sure the "Trigger frequency" dropdown in the **Event received** node has **One time** selected, as we only want to email each user once per event.
## Create your email
The next step is to create the email you send to each contact.
Click on the **Send email** node and then **Create email**. This will open the email editor, where you can [create your email](/creating-emails/editor).
![Adding event properties in the editor](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/scheduled-editor.png)
When you want to add the event properties you created in the previous step, click the `⚡️` button above the editor.
You will see a list of each event property, which you can then [insert into your email](/creating-emails/personalizing-emails). Make sure to [add fallback values](/creating-emails/personalizing-emails#fallback-values) for every property; if an event doesn't have a value for a property in your email, the email will not send. Fallback values make sure that emails are sent to every contact.
When you've finished creating your email, click **Start** in the top right. This will make your loop active and you can start triggering it by sending events.
## Trigger events
To send events to Loops you can use an [integration](/integrations), an [SDK](/sdks) or [our API](/api-reference).
With the API, it's just a case of making a request to the [Send event endpoint](https://loops.so/docs/api-reference/send-event) containing the contact's details, the event name and your event properties.
```json
{
"eventName": "sendDigest",
"email": "user1@gmail.com",
"eventProperties": {
...
}
}
```
## Learn more
Learn about creating email sequences in our loop builder.
Read more about triggering emails with events.
Learn how to add dynamic data to your emails.
Find out how to send events using our API.
# How to resend a campaign to new subscribers
A quick guide for sending a campaign to subscribers who signed up since you sent it out.
If you're regularly adding new subscribers via [a form](/forms), [integration](/integrations) or [the API](/api-reference), it's likely that you will want to send a campaign to new contacts who signed up after you sent it initially.
In Loops, you can do this in two easy steps: duplicating the campaign and filtering the audience.
## Duplicate the campaign
The first step is to duplicate the campaign so that you can send it out again.
To do this, go to the Campaigns page and click on the `•••` menu icon, then select **Duplicate**.
![Duplicating emails](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/duplicating-emails.png)
## Send to your new contacts
When you're ready to send the email, it's important that it only gets sent to contacts that haven't been sent it already.
To do this, on the **Audience** page of the sending flow, select "Not Sent" from the first dropdown and then the *original* campaign from the third dropdown.
![Filter audience by sent campaign](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/campaign-filter-resend.png)
This will update the total contacts and the table below, which will show contacts that were not sent the original campaign.
Check that everything looks OK and continue sending the email.
# What is BIMI?
And why does it matter?
As an email marketer, ensuring that your emails actually get seen and read is priority #1. Adding an avatar to your emails can increase your open rates by up to 21%. The familiarity and trust that this little avatar brings has a great impact on your email campaigns.
Outside of manually adding your brand’s logo as an avatar to each individual email client, there may actually be another way to ensure your emails have the same visual aid with additional layer of trust built in.
How? BIMI.
## What is BIMI?
BIMI, or Brand Indicators for Message Identification is a relatively new email standard that allows you to add your brand’s logo to your authenticated emails.
Adopting BIMI will allow your brand’s logo to appear next to your emails in your recipient’s inbox without manually needing to add and maintain it on a provider by provider level. As long as the email client supports BIMI, your logo will appear.
## Which email providers support BIMI?
A growing number of email provider’s are currently supporting BIMI with many more currently considering it. The current list of supported providers are:
* Gmail
* Google Workspace
* Apple Mail ([macOS Ventura 13, iOS 16, and iPadOS 16, or later](https://developer.apple.com/support/bimi/))
* AOL
* Netscape
* Fastmail
* Yahoo (Yahoo Japan is not currently supported but is under considering for future adoption)
* Pobox
Here is the full breakdown of who does and doesn’t support BIMI as of right now:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/R3P9DzvgnutHbbSomXep6ZOEOQ.webp)
Image via [BIMI Group](https://bimigroup.org/bimi-infographic/)
## How does BIMI actually work?
Setting up BIMI will take a bit more work than simply uploading your brand’s logo and hitting save.
Technically speaking, BIMI is a text file that lives on your sending servers and works hand in hand with DKIM, SPF, and DMARC protocols.
At a broad level, after you send an email, your recipient’s email provider will look up your BIMI text file and attempt to verify the legitimacy of it. Once verified, your BIMI text file points the email provider to where they can find your logo and they will then attach it to your email.
To start, the sender (you) will need to ensure that you are DMARC compliant. DMARC (domain-based Message Authentication, Reporting, & Conformance) is an [email authentication policy and reporting protocol](https://bimigroup.org/faqs-for-senders-esps/) that defends against unauthorized use of domains.
Basically, DMARC helps protect your brand by detecting emails that aren’t coming from your domain – preventing spoofing and phishing attempts.
The email provider will also run through the Sender Policy Framework (SPF) and DomainKeys Identified Mail (DKIM) protocols to ensure that the sender’s email address was sent from the correct domain.
Next, you will need to create the logo that will actually be used. The current recommendation is a [square SVG file](https://bimigroup.org/creating-bimi-svg-logo-files/).
The naming convention of this file should be:
`https://yourservername.com/logo.svg`
Next is an optional but recommended step. To fully embrace BIMI, your brand should acquire a VMC, or a Verified Mark Certificate. This will help validate the true ownership of the logo being used. More on this in the section below.
Finally, you will need to create a TXT record for BIMI in your DNS records. This record will contain a URL to your logo for the email provider to grab and display.
The full implementation guide from BIMI can be located [here](https://bimigroup.org/implementation-guide/).
## How much does BIMI cost?
Along with taking some technical chops to get BIMI fully set up, it’s also not free.
Getting the Verified Mark Certificate mentioned above currently [costs \$1,500](https://www.digicert.com/tls-ssl/verified-mark-certificates).
On top of this cost, to qualify for the certificate your brand logo also needs to be a registered trademark, which will also come with additional costs and possible legal fees.
## Checking your BIMI record
Now that you’ve gone through the work of setting up your BIMI records, it’s time to confirm that everything is working as expected.
The BIMI group provides a [BIMI inspector](https://bimigroup.org/bimi-generator/) where you can enter your domain to ensure everything is set.
## Implement BIMI, build trust
As you can see, fully embracing BIMI is a lengthy and potentially expensive process that may test your patience.
However, leaning into this new email standard positions your brand to gain your reader’s trust while limiting the manual labor and upkeep on your end to ensure that your brand’s logo is always at the forefront of their inboxes.
As the inbox becomes a more and more competitive landscape with each passing day, anything that you can do to stand out should be done.
BIMI just might give your brand the edge it needs to capture those sought after eyeballs.
# What is DNS?
A Beginner's Guide
Have you ever wondered how the internet seems to know precisely where to go when you type a website's name into your browser's address bar? How does your computer know to show you the right page when you type in "[www.loops.so](http://www.loops.so)"? The answer to these questions lies in the Domain Name System or DNS.
DNS is an essential part of the Internet's inner workings, serving as the Internet's equivalent of your iPhone’s address book. But what exactly is DNS, and why is it so important?
To understand DNS, we first need to understand how the Internet works. Let’s dive in!
## What is DNS?
Every device connected to the Internet, including computers, phones, and servers, has a unique IP address.
An IP address is a string of numbers separated by periods that identifies each computer using the Internet Protocol to communicate over a network. For example, an IP address might look like this: "192.168.0.1".
However, humans generally find it much easier to remember names rather than strings of numbers. This is where the **Domain Name System (DNS)** comes in. The DNS translates the domain names that we humans easily understand and remember into the IP addresses that computers use to identify each other on the network!
For instance, when you type in "[www.loops.so](http://www.loops.so)" into your web browser, your computer sends a request to a DNS server asking for the IP address associated with that domain name.
The DNS server responds with the IP address, and your computer then sends a request to that IP address to fetch and display the website.
The process of converting domain names into IP addresses is known as **DNS resolution**, and it usually takes only milliseconds. DNS servers are strategically located around the world and work together to ensure that these requests are processed quickly and accurately.
## Why is DNS important
Now, why is DNS crucial? Firstly, it makes the internet user-friendly.
Without DNS, we would have to memorize complex IP addresses for each website we wanted to visit. Secondly, it ensures the smooth operation of the internet. Every time you send an email, browse a website, or use an app, DNS is working behind the scenes to route your request to the right destination.
And if that wasn’t enough, DNS also provides a level of security. DNS servers can filter and block access to certain websites that might be harmful or inappropriate, providing an essential layer of protection for internet users. It helps you verify the authenticity of a sender via email as we’ll cover in the next section.
## DNS and email
DNS is vital for the functioning of email.
### Sending email
When you send an email, your email client needs to know where to send it.
Let's say you're sending an email to [someone@gmail.com](mailto:someone@gmail.com).
The client doesn't inherently know where "gmail.com" is, just like your web browser wouldn't know where to go if you entered that into the address bar. DNS steps in to resolve "gmail.com" into an IP address that represents the actual server your email needs to reach.
### Routing email to the right location
DNS is used for email routing, particularly through a type of DNS record called the MX (Mail Exchanger) record.
An MX record is a type of record that specifies a mail server responsible for accepting email messages on behalf of a recipient's domain.
A priority value (a number like 10 is typical) is used to prioritize mail delivery if multiple mail servers are available. Without the MX records, your email wouldn't know which server to go to.
### Security
Most importantly, DNS plays a critical role in email security.
For instance, Sender Policy Framework (SPF) and DomainKeys Identified Mail (DKIM) are two methods used to prevent email spoofing, a technique used in phishing and spam campaigns where the sender masquerades as another by forging the header data.
SPF and DKIM utilize DNS to hold text records that a recipient's server can check to verify the sender's identity.
In essence, DNS is a cornerstone for email operations and security. It helps your email find its way to the correct server, ensures the recipient's server can accept the mail, and provides mechanisms to verify the sender's identity to combat fraudulent activities. Without DNS, our email system would be far less reliable and secure.
## Send better email with Loops
In summary, the Domain Name System, or DNS, is a critical component of both the internet and email as a whole, transforming the web from a complicated network of numeric addresses into an accessible and secure environment for users worldwide.
It's the silent hero that allows us to navigate the digital world with ease, translating memorable website names into computer-friendly IP addresses.
So, the next time you browse the internet or send that time-sensitive email, take a moment to appreciate the extraordinary system that makes it all possible: **DNS**.
# Integrations
Loops integrates with thousands of other platforms so you can sync contacts and trigger emails from around the internet.
## Featured integrations
Sync customers to your audience and send automated emails.
}
href="/integrations/supabase"
>
Send Supabase authentication emails with Loops.
## Manage contacts
}
href="/integrations/bubble"
>
Manage contacts and send emails from your Bubble app.
}
href="/integrations/census"
>
Add contacts and contact properties from Census.
}
href="/integrations/clerk"
>
Sync users to your audience and send automated emails.
}
href="/integrations/framer"
>
Add a Loops signup form to your Framer site.
Sync outgoing mail contacts to HubSpot.
}
href="/integrations/integrately"
>
Manage contacts and send emails from over a thousand other platforms.
}
href="/integrations/make"
>
Manage contacts and send emails from thousands of other platforms.
Sync outgoing mail contacts to Salesforce.
}
href="/integrations/segment"
>
Manage contacts and trigger loops from thousands of other platforms.
Sync customers to your audience and send automated emails.
}
href="/integrations/webflow"
>
Add a Loops signup form to your Webflow site.
}
href="/integrations/zapier"
>
Manage contacts and send emails from thousands of other platforms.
## Send email
}
href="/integrations/auth0"
>
Send Auth0 authentication emails with Loops.
}
href="/integrations/bubble"
>
Manage contacts and send emails from your Bubble app.
}
href="/integrations/clerk"
>
Sync users to your audience and send automated emails.
}
href="/integrations/integrately"
>
Manage contacts and send emails from over a thousand other platforms.
}
href="/integrations/make"
>
Manage contacts and send emails from thousands of other platforms.
}
href="/integrations/segment"
>
Manage contacts and trigger loops from thousands of other platforms.
Sync customers to your audience and send automated emails.
}
href="/integrations/supabase"
>
Send Supabase authentication emails with Loops.
}
href="/integrations/zapier"
>
Manage contacts and send emails from thousands of other platforms.
## Create templates
Import custom MJML email templates from Emailify.
Import custom MJML email templates from Email Love.
# Auth0
Send Auth0 authentication emails with Loops.
Set up an SMTP connection to send all of your Auth0 emails with Loops.
There are two big benefits to using Loops for sending your Auth0 emails:
You can use [Loops' design editor](/creating-emails/editor) to create (and then easily edit) beautiful transactional emails instead of having to code them with HTML.
You get full visibility on which emails are being sent, when, and to whom in your Loops account. Auth0 doesn't offer this view.
## Set up Loops SMTP in Auth0
Go to **Branding -> Email Provider** in your Auth0 dashboard.
Scroll down and click on **SMTP Provider**.
In the SMTP Provider Settings section below, enter a value into the "From" field. This value will *always be overwritten by the values set in your Loops templates* from the next step, so it can be anything.
In the **SMTP Provider Settings** section enter the following data:
| Field | Value |
| ----------- | ------------------------------------------------------------------------------------------ |
| Host | `smtp.loops.so` |
| Port number | `587` |
| Username | `loops` |
| Password | An API key copied from your [API settings](http://app.loops.so/settings?page=api) in Loops |
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/auth0-smtp-settings.png)
The **Send Test Email** button here will not work due to how the Loops SMTP system works. You can test your connection in a later step.
## Create Transactional emails in Loops
Next, create new transactional emails for the emails you are sending from Auth0. Go to **Branding -> Email Templates** to view the full list.
[Read our guide for creating transactional emails](/transactional/guide#compose-your-email)
In Loops, go to the [Transactional page](https://app.loops.so/transactional) and click **New**. Alternatively, you can select one of our many ready-made templates from the [Templates page](https://app.loops.so/templates).
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/auth0-template.png)
You can then use [the Loops editor](/creating-emails/editor) to create nicely-designed templates or make them as simple as you like.
You can even [save styles](/creating-emails/styles#saved-styles) so you can easily apply consistent branding to all of your emails.
For each Loops template you create, you need to [add data variables](/creating-emails/personalizing-emails#add-dynamic-content-to-emails), which allow data from Auth0 to be inserted into each email.
You can check the list of [Common variables](https://auth0.com/docs/customize/email/email-templates#common-variables) supported in each email from the Auth0 documentation.
Once you're done creating the email and adding the data variables, click **Next**. On the next page, click the **Show payload** button to view the API payload for your template. You will need this for the next step.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/auth0-payload.png)
Make sure to also publish your email! It won't send unless it's published.
## Configure email templates in Auth0
The final step is to make sure your emails in Auth0 are configured to send the correct data to Loops.
Make sure you set up at least the **Verification Email (using Link)** or **Verification Email (using code)** templates in Auth0. Enable other emails based on your user flows.
Loops SMTP integrations work a bit differently than most. Instead of sending a text or HTML email body, you set them up to send API-like data.
In Auth0, go to **Branding -> Email Templates**, then edit each template to contain the payload as shown in the previous step (you can click the clipboard icon in Loops to copy the full payload).
Make sure that each template you want to use in Auth0 has the **Status** field enabled.
Once pasted into the **Message** body, you need to add the Auth0 message variables into the payload. You can do this using double curly brackets like `{{ url }}`.
Here is an example "Verification Email (using Link)" email template. This payload was copied from the template's Publish page in Loops, then the `{{ user.email }}` and `{{ url }}` Auth0 variables were added.
```json
{
"transactionalId": "clvmzp39u035tl50pw7wrl0ri",
"email": "{{ user.email }}",
"dataVariables": {
"productName": "{{ application.name }}",
"url": "{{ url }}"
}
}
```
Here's how it looks in the Auth0 editor:
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/auth0-email.png)
To test that everything works, click the **Try** button beneath the editor. Insert your email address in the modal that appears, then click **Try** to send the email.
You will also be able to see activity for your email sends in **Monitoring -> Logs**.
The best way to view your Auth0 email history is in Loops. Go to your [Transactional](https://app.loops.so/transactional) page then click on one of your emails. Click on **Metrics** in the left menu to view a page containing a table showing all sends and some statistics.
## Important notes
* The subject in Auth0 templates is always overwritten by the subject added to the corresponding template in Loops.
* The sender email configured in your Auth0 SMTP settings is always overwritten by the "From" address added to your templates in Loops.
* Any enabled Auth0 template not set up with the correct API-like payload will fail to send.
# Auto BCC
Import emails and contacts to your CRM by adding a BCC address to your marketing emails.
Our Auto BCC feature works with campaigns and loops, but is not offered on transactional emails.
By adding a BCC email address in your settings, your emails will be BCCd to this address.
Do not use a personal email address, only one generated by your CRM.
Auto BCC is a feature that imports emails and contacts into your CRM platform. This works by adding a BCC email address to all outgoing campaigns and loops emails sent from Loops.
You can add a BCC email address in your [Tracking settings page](https://app.loops.so/settings?page=tracking).
Be aware that BCCing might not be enough by itself. Some platforms may require you to add the sender email address to an allowlist or for the sender to be a user on your account.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/auto-bcc.png)
## Syncing with Salesforce
You can record all outgoing email and add contacts into Salesforce using a pre-generated Email to Salesforce address.
[How to find your Salesforce email address](https://support.cloudhq.net/where-do-i-find-my-bcc-address-in-salesforce/)\
[Read how Email to Salesforce works](https://help.salesforce.com/s/articleView?id=sf.email_my_email_2_sfdc.htm\&type=5)
## Syncing with HubSpot
You can log all outgoing emails and add new contacts to HubSpot using your pre-generated BCC address.
[How to find your HubSpot email address](https://knowledge.hubspot.com/settings/log-email-in-your-crm-with-the-bcc-or-forwarding-address)
Make sure to read the "Requirements to log emails to the CRM using the BCC address" section on the page above to make sure the sync works correctly.
## Syncing with Attio
With Attio, your Attio log in email has to match the sending email in Loops. This is a limitation within Attio.
For example, if your sending domain is `mail.mydomain.com` and the ["From" address](/sending-first-email#sending-settings) for your email is `bob@mail.mydomain.com`, your Attio account email has to be `bob@mail.mydomain.com` for this integration to work.
## Syncing with other CRMs
Most CRMs have a feature that lets you import email and contacts. Look for a BCC email address and add it to your Loops settings.
# Bubble
Integrate the Loops API into your Bubble app with our plugin.
Our Bubble plugin lets you:
* Add, find, update and delete contacts
* Send events to trigger loops
* Send transactional email
Our Bubble plugin is unfortunately limited to what it can do because of how Bubble works.
If you want more flexibility—for example, syncing more contact data to Loops—check out our [tutorial for using Bubble's API Connector](/guides/bubble-api-connector).
## Install the plugin
Go to the [Loops plugin](https://bubble.io/plugin/loops-1704117562175x705056703666192400) and select your app from the "Install in an application..." dropdown.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-install.png)
Alternatively, go to the Plugins page in your Bubble admin, click "Add plugins" in the top right, and search for "Loops".
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-search.png)
## Set up the plugin
To use the plugin you will need to add a Loops API key into Bubble.
First, go to your [Loops API settings page](https://app.loops.so/settings?page=api) and copy an API key. You may need to create a key first.
Then go to the the Plugins page in Bubble, select the Loops plugin and paste your API key into the "API key" field, prepended with the word "Bearer" and a space.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-api-key.png)
## Using the plugin actions
To use the plugin actions in a workflow, select "Plugins" in the menu and you will see the options show up (prefaced with "Loops - ").
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-action.png)
Here's a simple example of using the Bubble plugin to add all new users to your Loops audience.
After your sign up action, add a new "Loops - Create a contact" action.
In the form, add your user email into the "Email" field and user ID into the "User ID" field.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-form.png)
And that's it!
## Actions
The plugin contains actions that replicate what's possible with the [Loops API](/api-reference).
### Create a contact
The **Create a contact** action will create new contacts in Loops using the email address and user ID that you send from Bubble.
If you want to "create or update" users, use the [Update a contact](#update-a-contact) action instead.
You need to provide both email and user ID values, otherwise the underlying API request from Bubble will fail.
The **Create a contact with name** action lets you also send a first and last name to Loops.
[API documentation](/api-reference/create-contact)
### Find a contact
The **Find contact by email** action will find a Loops contact based on the provided email address. This can be used to see if one of your user already exists in your Loops audience.
Similarly the **Find contact by user ID** action will find a contact by their ID.
[API documentation](/api-reference/find-contact)
### Update a contact
This action will update the email address of a Loops contact who has the provided user ID.
This action can also be used to "update or create" contacts. If a contact doesn't already exist with the provided email or user ID, a contact will be created.
[API documentation](/api-reference/update-contact)
### Delete a contact
The actions **Delete a contact by email** and **Delete a contact bu user ID** will delete a contact from Loops.
This is useful for when a user closes their account in your application and therefore you no longer want to email them from Loops.
[API documentation](/api-reference/delete-contact)
### Send an event
The send event actions can be used to [trigger Loops](/loop-builder) from your application. For example, you may have a welcome loop which sends an email drip campaign to new users.
For the Send an event action, you need to provide an "Event name" value and the user's ID or email address.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-form.png)
[API documentation](/api-reference/send-event)
### Send transactional email
Transactional emails are one-time emails like password resets sent by apps to users based on an action.
To send transactional emails, you will first need to [create the email in Loops](/transactional/guide#compose-your-email).
Once you have written the email and added data variables, you can click **Next** to see the example payload for the API.
Note the names of the `dataVariables` (which you added in the email) because you need these in Bubble.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/bubble-transactional.png)
Once you create the action in Bubble, you will see the three fields in the form.
Here is an example API payload for the Loops API:
```json
{
"transactionalId": "clomzp89u635xl30px7wrl0ri",
"email": "name@email.com",
"dataVariables": {
"lastLoggedIn": "20240214T10:01:29Z",
"plan": "Pro",
}
}
```
To get the same effect in Bubble, we need to enter the following into the "Data variables" field:
`"lastLoggedIn": "20240214T10:01:29Z", "plan": "Pro"`
To add user data into this field, place your cursor and select **Insert dynamic data** (see image above).
[API documentation](/api-reference/send-transactional-email)
# Carrd
Enable sign ups to Loops using a native Carrd form.
### Add a form to your Carrd site
![carrd image](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/carrd.png)
1. Add a form to your site and select the **Custom** option.
2. Select **Send to URL** and paste in your form endpoint from the [Forms page in Loops](https://app.loops.so/forms).
![form endpoint](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/form-endpoint.png)
3. Paste the form endpoint you copied from into the **URL** input in Carrd.
4. Change the **Method** to "AJAX" and the **Format** to "JSON".
Our form submission endpoint has rate limiting, so you will see an error in testing if you
submit more than once per minute or submit the same email twice.
### Customizing the form
In addition to collecting the email address, you can also collect any other contact property you want.
1. Follow Carrd's documentation to [add a new field to your form](https://carrd.co/docs/forms/setting-up-a-custom-form)
2. Determine your preference:
* A hidden field that is set to a static value
* A value that your user can set
3. Assign the field an "ID" matching the Loops API property name that you want to set. You can check the full list of your available properties from your [API Settings](https://app.loops.so/settings?page=api) page.
For example, if you want to set the User Group property, you would add a hidden field and set the ID to `userGroup`.
To add subscribers to specific [mailing lists](/contacts/mailing-lists), add a field with an ID `mailingLists`. The **Value** can be a single mailing list ID or if you want to add subscribers to multiple lists, a comma-separated list of IDs.
# Census
Send user data from your data warehouse to Loops.
Our Census integration lets you:
* Create and update contacts
* Trigger loops when contacts are created or updated
Loops is a partnered destination for Census. We support syncing data via `userId` or `email`.
New contacts cannot be created if no email is provided.
Within the Census app, go to **Destinations** and click **+ New Destination**.
Select the **Loops** destination.
![Add Loops destination](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/census-loops-destination.png)
You will be prompted to enter your Loops API Token, which you can find on your [API settings page](https://app.loops.so/settings?page=api), and to decide if you want to trigger loops when contacts are created or updated.
![Create a destination](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/census-destination-modal.png)
Click **Connect** and test out your destination.
Loops will now be available as a destination in Census.
![Use the Loops destination](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/census-destination-loops.png)
When choosing a sync behavior, you can choose either **Update or Create** or **Mirror**.
![Choose sync behavior](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/census-sync-behavior.png)
# Clerk
Sync contacts and send emails triggered by events in Clerk.
Our Clerk integration lets you:
* Create and update contacts
* Send events to trigger loops
Our Clerk integration is built on top of our [Incoming webhooks](/integrations/incoming-webhooks) feature. This system lets you send webhooks from supported platforms directly to Loops so you can easily sync users and customers as well as send automated emails.
[Please read our guide about incoming webhooks](/integrations/incoming-webhooks)
With Clerk, you can keep your user data synced to Loops so you can easily send emails to your userbase.
## Synced data
We sync the following Clerk data to your Loops contacts for every incoming event:
* User ID
* Email address
* First name (optional)
* Last name (optional)
We use the IDs of Clerk users to match contacts in your Loops audience. If the user ID is not found in Loops, we will create a new contact.
## Supported events
We accept the following events:
* `user.created`
* `user.updated`
[Clerk webhook docs](https://clerk.com/docs/integrations/webhooks/overview)
If you send other events, they will be ignored.
If you would like to see more events supported, please let us know by sending
an email to [help@loops.so](mailto:help@loops.so). Please keep in mind only
events that contain an email address are able to be processed.
## Create a webhook endpoint in Loops
[Follow the instructions here](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops) to create a new webhook endpoint, which will allow you to send webhook events directly to Loops.
![Endpoint form](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-endpoint-clerk.png)
## Create a webhook in Clerk
Next, you need to set up webhooks in Clerk.
Go to **Webhooks** and click **+ Add Endpoint**. Paste in the endpoint URL from Loops, then select the event(s) you want to send (see our [supported events](#supported-events) above).
![Adding a webhook in Clerk](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/clerk-webhook.png)
Click **Create** to finish.
The last step is to copy the signing secret into Loops. On the webhook page in Clerk, click the eye icon on the right to show the secret in the page. Copy the secret and paste it into the **Signing Secret** field in Loops.
![Reveal Clerk secret](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/clerk-secret.png)
Now you're all set up.
## Testing Clerk webhooks
Clerk offers a nice way to test webhooks. Click through to the webhook you created and then the **Testing** tab.
Select `user.created` or `user.updated` from the **Send event** dropdown, tweak the example data that's shown, then click **Send Example**.
This will send real data to your Loops account.
You can also test your webhook by creating and editing users in the **Users** page in Clerk, or by signing up in your application.
You can see all sent webhooks by going to **Webhooks**, clicking on the webhook and scrolling down to the **Message Attempts** section.
On Loops' end, you will see new contacts appear in your [Audience](https://app.loops.so/audience) page, and triggered events in the [Events](https://app.loops.so/settings?page=events) page.
## Examples
Here are some examples of how you can send data from Stripe to Loops to sync contacts and trigger useful emails to your customers.
### Syncing users to Loops
Create or update contacts in your Loops audience when a user is created or updated in Clerk.
1. Create a new Clerk webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
2. In Clerk, create a new webhook ([instructions above](#create-a-webhook-in-clerk)) for the `user.created` and `user.updated` events and paste in your endpoint's URL.
3. In Loops, make sure `user.created` and `user.updated` are checked on the Clerk settings page.
### Send an email to all new Clerk users
Send an email from Loops when a new user is created in Clerk.
1. Create a new loop in Loops using our **Onboarding drip** template.
2. For the loop trigger, select **Event received** and enter `newClerkUser` (or something similar).
3. Set up your Clerk webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
4. In Clerk, create a new webhook ([instructions above](#create-a-webhook-in-clerk)) for the `user.created` event and paste in your endpoint's URL.
5. In Loops, make sure `user.created` is checked, and select the event name you chose in Step 2 from the **Trigger an event** field.
### Enter all new Clerk users into an onboarding email sequence
Send an email from Loops when a new customer is created in Clerk.
1. Complete Steps 1–5 from "Send an email to all new Clerk users" above.
2. Add more emails and timers into the loop to complete your email sequence.
# Framer
Enable signups from your Framer site using an in-built or custom Loops component.
Collect new subscribers from your Framer site. There are a few ways to set this up.
## Framer Form component
Use [Framer Forms](https://www.framer.com/features/forms/) to easily create a form on your site.
### Insert the Form Component
From **Insert -> Forms** drag the **Form builder** component into your page. This will add an example form.
![Framer Form component](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-form-component.png)
### Edit the form fields
Edit the fields in the form to match the data you want to collect from new subscribers.
An email field is required. Make sure to toggle the **Required** option to **Yes** for your email field.
You need to edit the **Name** value of each field to match the [contact properties' "API name"](/contacts/properties) in Loops.
For example, the **Name** value must be "email" for the email address field.
![Email form field](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-email-field.png)
You can add hidden fields to populate data like `mailingLists`, `userGroup` and `source` in Loops yet ensure they don't show up in the form.
You may have to click the `+` button to add the **Value** and **Hidden** options.
To add subscribers to specific [mailing lists](/contacts/mailing-lists), add a field with **Name** `mailingLists`. The **Value** can be a single mailing list ID or a comma-separated list of IDs.
![Hidden form field](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-form-hidden.png)
### Configure the form
The final step is to set the endpoint to your Loops form URL.
1. Go to the [Forms page](https://app.loops.so/forms) in your Loops account.
2. Click on the **Settings** tab.
3. Copy the **Form Endpoint**.
![Form endpoint](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/form-endpoint.png)
4. Back in Framer, select your form. In the **Send To** option, select "Webhook". Then paste the URL from Loops into the **API** field.
![Framer form webhook](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-form-webhook.png)
Now your form is all set up and can start receiving new subscribers.
### Set up a confirmation message
By default a "Thank you" message is shown inside the form button when the form is submitted successfully.
You can opt to use a redirect instead. You can add a confirmation message on another web page and use the **Redirect** option in the form settings.
## Framer Loops component
Framer has a built-in Loops option for creating simple signup forms with an email address field.
### Insert the Loops Component
From **Insert -> Forms** drag the **Loops** component into your page. This will add an example form.
![Framer Loops component](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-loops-component.png)
### Configure the form
Next, you need to add your Loops form ID to the **ID** field.
1. Go to the [Forms page](https://app.loops.so/forms) in your Loops account.
2. Click on the **Settings** tab.
3. Copy the **Form ID**.
![Form ID](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/form-id.png)
4. Paste this ID into the **ID** field in the Framer component.
![Loops form ID](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-property-panel.png)
5. Framer offers a **User Group** option in the component, which will populate the contact's `userGroup` value in Loops.
### Set up a confirmation message
Make sure to also set up a confirmation message by clicking on the **Success** dropdown.
You can choose to show a message in an overlay or redirect the user to another web page.
## Advanced integration
This option adds a custom component into your Framer site [using form code](/forms/custom-form) generated by Loops
### Generate the form code
1. Go to the [Forms page](https://app.loops.so/forms) in your Loops account.
2. Click on the **Settings** tab.
3. Select “JSX” from the **Generate Form Code** dropdown (1), then copy the code snippet (2).
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/jsx-form.png)
### Embed the component in Framer
1. Create a new component. Toggle over to **Assets** in the Framer side panel then click the `+` button.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-1.png)
2. Give your New Component a title.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-2.png)
3. Finally, paste the code copied in from Loops into the code editor. You should see the Preview on the right fill in with a preview of your component.
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/framer-3.png)
4. Drag and drop your new asset anywhere on your page to use it :)
Our form submission endpoint has rate limiting, so you will see an error in testing if you
submit more than once per minute or submit the same email twice.
# Incoming webhooks
Send data to Loops from supported platforms using webhooks.
Incoming webhooks allow you to:
* Create and update contacts
* Send events to trigger loops
This feature lets external platforms send webhook events directly to Loops, making it straightforward to create or update contacts in Loops automatically when changes happen in other platforms.
You can also trigger events when webhooks arrive in Loops so you can send automated email after something happens in your other accounts.
## How it works
First, you create webhook endpoints in your Loops account. These allow other platforms to send data automatically and directly to Loops.
You then create webhooks in the external platforms, which send event data to your Loops endpoint URLs.
Note: we only process webhook events listed below for each provider (and which contain an email address).
We return helpful messages in responses if there is an issue processing a webhook event. Check the webhook logs in your external platforms.
### Syncing contacts
When data arrives in Loops, we grab the email address to create and update contacts in your Loops audience.
For each endpoint you create you can choose to assign a user group value to each new contact, allowing you to create segments from webhook-created contacts.
Any new contact created via a webhook will have a source like "Stripe webhook" so you know where it originated from.
### Sending emails
We also support triggering events for each incoming webhook event. This can be useful to automatically send emails when a webhook event arrives in Loops (e.g. a successful payment or a new customer).
## Create webhook endpoints in Loops
To start sending webhook events to Loops, go to your chosen [integration's settings page](https://app.loops.so/settings) in Loops.
A webhook endpoint will be created for you. Copy the endpoint URL and paste it into your external platform.
![Endpoint form](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-endpoint.png)
You may need to copy-paste signing secrets between the platform and Loops for extra security (we will prompt you when this is necessary and give you the steps to do it).
In the endpoint form, you can select the events you want Loops to process, assign a user group, and send a Loops event (which can [trigger email sending in loops](/loop-builder#triggers)).
## Supported platforms
* [Clerk](/integrations/clerk)
* [Stripe](/integrations/stripe)
* More coming soon!
# Integrately
Connect Loops to over a thousand apps.
Our Integrately integration lets you:
* Create, find, update and delete contacts
* Send events to trigger loops
* Send transactional email
## Create an automation
In Integrately, create an automation by searching for and selecting the two platforms you want to connect.
![Add an automation in Integrately](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/integrately-add.png)
You'll need to connect to or sign in to each platform. When it comes to connecting to Loops, you need to create or copy an API key from [your API Settings page](https://app.loops.so/settings?page=api). Paste your API key into Integrately.
![Add Loops API key](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/integrately-api.png)
Now you are connected to Loops and can continue setting up the automation.
## Manage contacts
To sync contacts, choose either the "Create contact" or "Create or update contact" action.
You can map data between the two platforms in the automation form. In this example, the "Email" field contains the data from the "Email" column in Google Sheets.
![Create a contact automation](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/integrately-contact.png)
## Send event
To send events from Integrately (i.e. to trigger [sending a loop](/loop-builder)), choose the "Send event" action and then map an "Email" and "Event name" in the available fields.
![Send event automation](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/integrately-event.png)
## Send transactional email
To send transactional email from Integrately, select the "Send transactional email" action.
Map the email address you want to send to. Then add the ID of your transactional email from Loops (found on the "Publish" page of the transactional email editor).
Finally, add your email's data variables. You can easily map dynamic variables from the source app or add static text in the form.
![Send transactional email automation](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/integrately-transactional.png)
# Make
Utilize our official Make integration to manage contacts and send email.
Our Make integration lets you:
* Create, find, update and delete contacts
* Send events to trigger loops
* Send transactional email
## Create a connection
Before you get started, head over to the API page and [create a new API key](https://app.loops.so/settings?page=api) in Loops. You'll need to copy the API key and paste it into Make.
To get started create a new scenario and select the "Loops" module.
![Adding loops in Make](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/make-loops.png)
Then select the "Create Connection" button and paste in your API key in the following screen.
![Create a connection with Make](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/make-add-create-connection.png)
After pasting your API key, click the "Save" button.
![Connect Loops API with Make](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/make-paste-api-key.png)
## Manage contacts and trigger loops
There are a number of actions available to manage contacts and send emails.
![Adding a module with Make](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/make-add-module.png)
## Send transactional email
The Make integration does not have a specific action for sending transactional email. Instead you can use the "Make an API call" action.
![Set up transactional sending in Make](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/maketransactional.png)
Make sure that the URL is `/v1/transactional` rather than the full endpoint URL.
You can copy an email's example payload from its Publish page in Loops by clicking the **Show payload** button. Paste it into the "Body" field in Make and select the data you want to send to Loops.
View the API reference for sending transactional email.
# Segment
Utilize our official Segment integration to manage contacts and send email.
Our Segment integration lets you:
* Create and update contacts
* Send events to trigger loops
Visit our [Segment integration](https://segment.com/catalog/integrations/actions-loops/) to learn more and follow the steps below.
## Configuring the destination
After opening the link above, click **Configure Loops (Actions)**.
![Adding Loops in Segment](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-configure-loops.png)
Select your data source, give the destination a name, and click **Create destination**.
Next, you’ll need an API key. You can generate a new one for Segment on the [Loops API Settings page](https://app.loops.so/settings?page=api).
Enter the API key on your Segment destination settings:
![Add an API key](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-api-key.png)
Enable the destination and click **Save Changes**. Note that no data will start flowing until you create specific mappings for Loops.
## Mappings
Segment action destinations require that you map specific fields from your source to your destination (in this case Loops). You can set this up by clicking into the **Mappings** tab and adding a new mapping. Currently we support updating contacts in Loops and sending events into Loops.
### Create or update contact
First, select which events to map. Typically for contact creation and updates, the most useful event to map will be "Identify".
![Map contact properties](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-select-events.png)
The next step is to load a sample event to help you map fields appropriately.
Contact properties are found in the `traits` object.
For this example, we’ll be using this test event:
```json
{
"messageId": "segment-test-message-gt3ds8",
"timestamp": "2023-05-24T17:58:30.352Z",
"type": "identify",
"email": "adam@loops.so",
"traits": {
"firstName": "Adam",
"favoriteColor": "blue",
"favoriteNumber": 42
},
"userId": "test-user-a5h7xb"
}
```
When sending a contact's details to Loops, you must include an Email and a User ID.
We've provided some defaults for the mappings, which will show up in the third step, but it is important you review them:
![Default contact mappings](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-default-mapping.png)
#### Custom contact properties
Segment does not provide an interface to provide the names and types for [custom contact properties](/contacts/properties#custom-contact-properties) that you might be using with Loops. In our example, those fields are `favoriteColor` and `favoriteNumber`.
You can pass contact properties as a dictionary in the **Custom Contact Attributes** field.
Ensure that the keys and values you provide match the schema you’ve created in your [Contact properties settings](https://app.loops.so/settings?page=api).
Click **Edit Object** to specify the custom fields you want to send to Loops individually:
![Mapping custom contact properties](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-edit-defaults.png)
#### Subscribed
In most cases, you want to leave the **Subscribed** field as the default (deselected). Setting this to `true` will re-subscribe contacts who had previously unsubscribed, and setting it to `false` will unsubscribe contacts from receiving email. Leaving it deselected will default new users as subscribed to email and not update the email preference for existing contacts.
![Subscribed field](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-subscribed-field.png)
#### Mailing lists
To subscribe contacts to [mailing lists](/contacts/mailing-lists) there are two options.
The first method is to manually edit the **Mailing Lists** data. This will allow you to enter list ID values that are the same for every contact.
Click the **Edit Object** option, then the **+ Add Mapping Field** button. In the **Select event variable** field enter "true" or "false" (to subscribe or unsubscribe) and in the **Enter key name** field enter your list ID(s).
You can add multiple lists by clicking on the **+ Add Mapping Field** button again. Make sure the data shown below the fields has the same structure as in the image below.
![Adding list IDs in the mapping UI](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-mapping-lists.png)
Another option is to add mailing list data to your Identify call, which will let you dd more dynamic data for each contact. You can test this by adding a `mailingLists` object to `traits` in your test event with list IDs as keys and `true` (to subscribe) or `false` (to unsubscribe) as values.
```json
{
"messageId": "segment-test-message-gt3ds8",
"timestamp": "2023-05-24T17:58:30.352Z",
"type": "identify",
"email": "adam@loops.so",
"traits": {
"firstName": "Adam",
"favoriteColor": "blue",
"favoriteNumber": 42,
"mailingLists": {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": true,
}
},
"userId": "test-user-a5h7xb"
}
```
Then you need to map the data. Click the **Select Object** option, then search for `traits.mailingLists` from the Event Variables options.
![Selecting the mailing list data from traits](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-mailinglists-object.png)
#### Testing
After the mappings are configured you can preview the data that will be sent.
![Event data preview](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-test-preview.png)
You can also send a test event to Loops to verify everything is working (this will send actual data to your Loops account). If it works, you will get a successful response:
![Successful response](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-test-event.png)
Check your [Loops audience page](https://app.loops.so/audience) to ensure the contact was created or updated as intended.
Sending another test event with the same User ID or Email will update the existing contact instead of creating a new contact.
### Send event
You can send events to trigger [loops](/loop-builder).
First, select which events to map. Typically for sending an event, the most useful event to map will be "Track". It’s suggested you filter the events down to only ones that you plan on using within Loops using the **Event Name** filter:
![Sent event in Segment](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-send-event.png)
Then after defining or loading a sample event in step 2, configure the mapping.
If you want to add [event properties](/events/properties), you can pass them as a dictionary to the **Event Properties** field. Click **Edit Object** to map the properties to your event property names. Add property names in the "Enter key name" fields and either enter or select values in the "Select event variable" fields.
![Configure event mappings](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-configure-mappings.png)
If a contact already exists in your Loops audience, the **Contact Email** field is optional. Loops will trigger based on the **User ID**. If the contact does not exist in your Loops audience (perhaps you are not using an identify call), you will need to provide an email address otherwise Loops will not be able to create the contact for the event.
#### Testing
After configuring the mapping, you can send a test event at the bottom of the page (this will send actual data to your Loops account). You can preview the data that will be sent.
![Send event preview](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-event-preview.png)
The response should indicate success:
![Success message](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/segment-test-mappings.png)
You can verify the event was received on your [Events page](https://app.loops.so/settings?page=events) in Loops.
## Sending data to Segment
The following examples show how you can send data from your application to Segment for the two Loops actions.
The examples use Segment's [Analytics.js library](https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/), but the premise is similar for other libraries.
### Create or update contact
For this action you should send a `identify()` event. Add contact properties (including any [custom properties](/contacts/properties#custom-contact-properties)) in the traits object:
```javascript
analytics.identify("97980cfea0067", {
email: "peter@example.com",
plan: "premium",
logins: 5
});
```
If you're mapping a `mailingLists` object from `traits` ([read more above](#mailing-lists)) add it like this:
```javascript
analytics.identify("97980cfea0067", {
email: "peter@example.com",
plan: "premium",
logins: 5,
mailingLists: {
"cm06f5v0e45nf0ml5754o9cix": true,
"cm16k73gq014h0mmj5b6jdi9r": true,
}
});
```
### Send event
For this action send a `track()` event. Data sent in the properties object will be sent as [event properties](/events/properties) to Loops. Make sure that you have added these event properties in your [Events Settings](https://app.loops.so/settings?page=events).
```javascript
analytics.track("User Registered", {
plan: "Pro Annual",
accountType: "Facebook"
});
```
You have the option to update contacts when sending events by adding contact properties in a `context` object.
```javascript
analytics.track("User Registered", {
plan: "Pro Annual",
accountType: "Facebook",
},
{
traits: {
firstName: "Phil"
}
});
```
# Stripe
Sync contacts and send emails triggered by events in Stripe.
Our Stripe integration lets you:
* Create and update contacts
* Send events to trigger loops
Our Stripe integration is built on top of our [Incoming webhooks](/integrations/incoming-webhooks) feature. This system lets you send webhooks from supported platforms directly to Loops so you can easily sync users and customers as well as send automated emails.
[Please read our guide about incoming webhooks](/integrations/incoming-webhooks)
With Stripe, you can sync user data to Loops for customer and invoice-related events.
## Synced data
We sync the following Stripe data to your Loops contacts for every incoming event:
* Email address
* First and last name (optional)
We use the email addresses of Stripe customers to match contacts in your Loops audience. If the email address is not found in Loops, we will create a new contact.
## Supported events
We accept the following events:
* `customer.created`
* `customer.updated`
* `invoice.paid`
* `invoice.payment_failed`
* `invoice.upcoming`
[Stripe webhook docs](https://docs.stripe.com/webhooks)
If you send other events, they will be ignored.
If you would like to see more events supported, please let us know by sending
an email to [help@loops.so](mailto:help@loops.so). Please keep in mind only
events that contain an email address are able to be processed.
## Create a webhook endpoint in Loops
[Follow the instructions here](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops) to create a new webhook endpoint, which will allow you to send webhook events directly to Loops.
![Endpoint form](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/create-endpoint.png)
## Create a webhook in Stripe
Next, you need to set up webhooks in Stripe.
Go to **Developers** and then **[Webhooks](https://dashboard.stripe.com/webhooks)**.
Click **+ Add endpoint**. Paste in the endpoint URL from Loops, then select the event(s) you want to send (see our [supported events](#supported-events) above).
![Adding a webhook in Stripe](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/stripe-webhook.png)
Click **Add endpoint** to finish.
The last step is to copy the signing secret into Loops. On the webhook page in Stripe, click **Reveal** to show the secret in the page. Copy the secret and paste it into the **Signing Secret** field in Loops.
![Reveal Stripe secret](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/stripe-secret.png)
Now you're all set up.
## Testing Stripe webhooks
You can test a `customer.*` webhook by creating a new customer in the [Customers](https://dashboard.stripe.com/customers) page in Stripe.
You can also use the Stripe CLI tool to mimic events, by using the [`trigger` command](https://docs.stripe.com/cli/trigger).
You can see all sent webhooks by going to **Developers -> Webhooks** and then clicking on an endpoint.
On Loops' end, You will see new contacts appear in your [Audience](https://app.loops.so/audience) page, and triggered events in the [Events](https://app.loops.so/settings?page=events) page.
## Examples
Here are some examples of how you can send data from Stripe to Loops to sync contacts and trigger useful emails to your customers.
### Syncing customers to Loops
Create or update contacts in your Loops audience when a customer is created or updated in Stripe.
1. Create a new Stripe webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
2. In Stripe, create a new webhook ([instructions above](#create-a-webhook-in-stripe)) for the `customer.created` and `customer.updated` events and paste in your endpoint's URL.
3. In Loops, make sure `customer.created` and `customer.updated` are checked on the Stripe settings page.
### Send an email to all new Stripe customers
Send an email from Loops when a new customer is created in Stripe.
1. Create a new loop in Loops using our **Stripe - New Customer** template.
2. For the loop trigger, select **Event received** and enter `newStripeCustomer` (or something similar).
3. Set up your Stripe webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
4. In Stripe, create a new webhook ([instructions above](#create-a-webhook-in-stripe)) for the `customer.created` event and paste in your endpoint's URL.
5. In Loops, make sure `customer.created` is checked, and select the event name you chose in Step 2 from the **Trigger an event** field.
### Successful payment email
Send an email from Loops when an invoice is paid in Stripe.
1. Create a new loop in Loops using our **Stripe - Payment Successful** template.
2. For the loop trigger, select **Event received** and enter `successfulPayment` (or something similar).
3. Set up your Stripe webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
4. In Stripe, create a new webhook ([instructions above](#create-a-webhook-in-stripe)) for the `invoice.paid` event and paste in your endpoint's URL.
5. In Loops, make sure `invoice.paid` is checked, and select the event name you chose in Step 2 from the **Trigger an event** field.
### Failed payment email
Send an email from Loops when an invoice payment fails in Stripe.
1. Create a new loop in Loops using our **Stripe - Payment Failed** template.
2. For the loop trigger, select **Event received** and enter `failedPayment` (or something similar).
3. Set up your Stripe webhook endpoint in Loops ([instructions](/integrations/incoming-webhooks#create-webhook-endpoints-in-loops)).
4. In Stripe, create a new webhook ([instructions above](#create-a-webhook-in-stripe)) for the `invoice.payment_failed` event and paste in your endpoint's URL.
5. In Loops, make sure `invoice.payment_failed` is checked, and select the event name you chose in Step 2 from the **Trigger an event** field.
# Supabase
Configure your Supabase account to send authentication emails with Loops.
Set up an SMTP connection to send all of your Supabase emails with Loops.
There are two big benefits to using Loops for sending your Supabase emails:
You can use [Loops' design editor](/creating-emails/editor) to create (and then easily edit) beautiful transactional emails instead of having to code them with HTML.
You get full visibility on which emails are being sent, when, and to whom in your Loops account. Supabase doesn't offer this view.
## Set up Loops SMTP in Supabase
Go to your Authentication settings in Supabase (**Project Settings -> Authentication**) to tell Supabase to send emails using Loops' SMTP service.
Scroll down and toggle the **Enable Custom SMTP** option on.
In the Sender details section, you will need to enter some values into the "Sender email" and "Sender name" fields. However, *these values will always be overwritten by the values set in your Loops templates* from the next step.
In the **SMTP Provider Settings** section enter the following data:
| Field | Value |
| ----------- | ------------------------------------------------------------------------------------------ |
| Host | `smtp.loops.so` |
| Port number | `587` |
| Username | `loops` |
| Password | An API key copied from your [API settings](http://app.loops.so/settings?page=api) in Loops |
![](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-smtp-settings.png)
Note that for the interval and rate limit settings, you will be bound by Loops' [API rate limit](/api-reference/intro#rate-limiting) of 10 requests per second.
One final step is to check that the "Confirm email" toggle is turned on in the Email section in **Authentication -> Providers**.
## Create Transactional emails in Loops
Next, create new transactional emails for the emails listed in Supabase (**Authentication -> Email Templates**). You need to create both **Confirm signup** and **Magic Link** emails to be able to properly set up the integration.
* Confirm signup (required)
* Invite user
* Magic Link (required)
* Change Email Address
* Reset Password
Note that if a Supabase user has not previously confirmed their email, they will be sent a **Confirm signup** email when you request a **Magic Link** email.
To create new transactional emails, go to the [Transactional page](https://app.loops.so/transactional) in Loops and click **New**. Alternatively, you can select one of our many ready-made templates from the [Templates page](https://app.loops.so/templates).
![Supabase template in the editor](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-template.png)
You can then use [the Loops editor](/creating-emails/editor) to create nicely-designed templates or make them as simple as you like.
You can even [save styles](/creating-emails/styles#saved-styles) so you can easily apply consistent branding to all of your emails.
![Saved styles](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-editor.png)
For each Loops template you create, you need to [add data variables](/creating-emails/personalizing-emails#add-dynamic-content-to-emails), which allow data from Supabase to be inserted into each email.
For example, you could add a `confirmationUrl` data variable that you can map to the `{{ .ConfirmationURL }}` value from Supabase.
You can also build URLs by including values like `{{ .SiteUrl }}` or add in a confirmation code using `{{ .Token }}`.
![Supabase values](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-values.png)
Once you're done creating the email and adding data variables, click **Next**. On the next page, click the **Show payload** button to view the API payload for your template. You will need this for the next step.
![Email payload](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-payload.png)
Make sure to also publish your email! It won't send unless it's published.
Read our detailed guide for sending transactional emails.
## Configure email templates in Supabase
The final step is to make sure your emails in Supabase are configured to send the correct data to Loops.
Loops SMTP integrations work a bit differently than most. Instead of sending a text or HTML email body, you set them up to send API-like data.
In Supabase, go to **Authentication -> Email Templates**, then edit each template to contain the payload as shown in the previous step (you can click the clipboard icon in Loops to copy the full payload).
Once pasted into the Message body, you need to add the Supabase message variables into the payload.
Make sure you set up at least the **Confirm signup** and **Magic Link** templates in Supabase, otherwise emails will not be sent.\
Also, any variables added in the **Confirm signup** template need to also be available in **Magic link** email, because Supabase will send a **Confirm signup** email instead of a **Magic Link** email if a user hasn't confirmed their email address.
Here is an example **Confirm signup** email template. This payload was copied from the template's Publish page in Loops, then the `{{ .Email }}` and `{{ .ConfirmationURL }}` Supabase variables were added.
```json
{
"transactionalId": "clvmzp39u035tl50pw7wrl0ri",
"email": "{{ .Email }}",
"dataVariables": {
"confirmationUrl": "{{ .ConfirmationURL }}"
}
}
```
Here's how it looks in the Supabase editor:
![Supabase editor](https://mintlify.s3-us-west-1.amazonaws.com/loops/images/supabase-email.png)
With the integration now all set up, your Supabase authentication emails will be sent via Loops, giving you more visibility on your email sends and the great addition of being able to build beautiful and easy-to-update emails in the Loops editor.
To view all sends of your transactional emails, click through to the email from the [Transactional](https://app.loops.so/transactional) page in Loops, where you'll find the Metrics page containing a table showing all sends and some statistics.
## Important notes
* You need to add a template in Loops and set up the email in Supabase for at least the **Confirm signup** and **Magic Link** templates.
* The subject in Supabase templates is always overwritten by the subject added to the corresponding template in Loops.
* The sender name and sender email configured in your Supabase SMTP settings are always overwritten by the sender details added to your templates in Loops.
* Any Supabase email not set up with the correct API-like payload will fail to send.
# Webflow
Enable signups from your site using a native Webflow form.
This integration requires a paid Webflow plan to allow embedding custom
scripts into your site.
To allow sign ups to your audience from your Webflow site, you can utilise a native Webflow form plus some drop-in JavaScript.
## Add a custom form script to your Webflow site
If you do not add the custom script in the correct place, the form may not
work properly.
To submit data to Loops seamlessly from your Webflow site we provide some JavaScript, which can be added to your site.
Use this script in your Webflow page.
### Where to add the script
* If you have a Loops form on every page of your site, add this code to the "Footer code" section in your Site settings ([read how in the Webflow docs](https://university.webflow.com/lesson/custom-code-in-the-head-and-body-tags#custom-code-in-site-settings)).
* If you have a Loops form on only one page, add this code to the "Before \