Objects
An object is a business thing you want to keep track of: an account, subscription, order, product or course. It has its own record and fields. Connect it to the people it matters to, then use those facts to choose an audience and personalize their email.
The contact receives the message. The object explains the context. Maya is a contact; Studio North, the account she belongs to, is an object. Sarah is a contact; each order she places is a separate object. Neither an account nor an order becomes an email recipient.
When to use an object
Use an object when something has its own identity, changes independently, is shared by several people, or can occur several times for one person.
- Product adoption: keep the user's identity and preferences on the contact. Store their shared account and individual projects as objects.
- Renewal reminders: keep each subscription's status, plan and renewal date on its own object, then find the person who owns it.
- Repeat purchase: keep each order's amount, purchase date and status separately, linked to the shopper who placed it.
- Course recommendations: keep each course's title, schedule and availability on a Course object, ready to use with the relevant students.
A simple personal preference can stay as a contact attribute. Repeated orders should not become order1, order2 and order3 fields on the person. Separate Order records let you ask for that shopper's most recent order or count all qualifying purchases.
An object schema is the kind of thing, such as Account. An object record is one instance, such as Studio North. A JSON object is only a structured value inside a field; it does not create a separate business record or relationship.
How objects connect to people
Store the identifiers on both sides, then define an evaluated relationship that matches them. A field containing an ID is the input to that rule; naming it accountId does not create the relationship automatically.
Here is an illustrative account setup. accountId, accountRole, accountName and plan are custom fields you create first; externalId is built in.
- Maya, a Customer contact:
accountIdisstudio-north;accountRoleisadmin. - Daniel, another Customer contact: the same
accountId;accountRoleismember. - Studio North, one Account object:
externalIdisstudio-north,accountNameisStudio North, andplanisPro.
Both people should resolve to the same Account record, while keeping their own role and communication preferences.
On Customer, create an Evaluated attribute named Account with the key account. Describe it like this:
Return the Account whose externalId equals this Customer's accountId. Return one Account, or no record if accountId is empty or no match exists.
Check that the generated definition targets Account with one cardinality. On Maya and Daniel's profiles, Compute value should resolve to the same account. A customer with no matching account should return no record.
You can then build a segment of admins whose related account is on Pro: Maya qualifies and Daniel does not. In the email's Data panel, select account to make its name and plan available to the content. The shared object supplies the context; each contact's preferences still decide whether they can receive marketing email.
For commerce, reverse the lookup: on Customer, define Recent orders to return Orders whose custom customerId equals that Customer's userId, with a completed-status filter, newest first and a useful limit. That relationship returns many records. See Connecting records for the complete setup and checks.
Create the object type
Go to Settings, then Schemas, and choose Create schema. Set the type to Object, then fill in the name ("Product"), the plural name ("Products"), a slug, and a description.
One type per kind of thing. Products and Orders are two types, not one. Every object belongs to exactly one type and is checked against it each time it is written, which is what your segments, emails and workflows rely on to find the fields there.
Write the description for a person to read. maxinja reads it too, every time it builds a segment, an evaluated attribute or workflow logic that touches this object.
Add your fields
Open the type, go to the Attributes tab, and use Create attribute for each field you need: price, SKU, colour, launch date. The available field types are covered in attributes.
Every object comes with these already, whatever else you add:
| Field | What it is for |
|---|---|
| ID | The identifier maxclicks gives it. |
| External ID | Your own identifier for the same thing, from your store or database. |
| Notes | Free text. |
| Tags | Labels you can filter and act on. |
| Created At, Updated At | Kept by maxclicks. |
Two of your own fields are worth naming deliberately, because the app reads them:
- A single-line Text field whose key contains
name,titleorlabelbecomes the heading on the object's page, soproductNamecounts. Without one, maxclicks falls back to your first single-line text field, and then to the External ID. - A URL field with its target set to Image becomes the thumbnail in the objects table.
Give every object an External ID
Supply the platform id to identify an existing object directly, or your source system's stable externalId to match within the object schema. Repeatedly upserting that external ID updates the same object. Names, prices and other custom fields do not establish identity.
Without either identifier, repeated writes can create repeated records. A Product and an Order can use the same external ID without colliding because matching stays within the selected schema. Sending a platform ID that is not found does not mean “create this exact ID”; inspect the operation's error or unmatched result.
No two objects of the same type can hold the same External ID. Over the upsert endpoint and from a workflow step, an update that would take one already belonging to another object keeps the old value, applies everything else you sent, and reports the change it skipped. Everywhere else the conflicting write is not applied at all: a clashing CSV row is counted as a failed row, with "Conflicting external ID." against it in the import's failure log, editing the field to a taken value in the app fails with a conflict error, and creating or patching a record over the API returns a conflict. Check those warnings and failed rows: a skipped or rejected External ID means your sync is pointing two things at one identifier.
Get your objects in
| Route | Use it for |
|---|---|
| The Import tab on the object type | An existing spreadsheet, with one object per row. |
| The button above the table, labelled New and then your type's name | One object, by hand. |
| The API | Your store, database or backend keeping maxclicks in sync. See Records. |
| A connected app | Integrations bring their own object types and keep them up to date for you. |
For CSV, download the schema's sample, fill it with your objects and upload it. Files can contain up to 50 MB and 500,000 rows. The standard importer matches writable field keys and omits unknown columns; inspect saved objects because the row summary does not show per-column warnings. Onboarding can instead plan a reviewed mapping with maxinja. The import guide covers the shared CSV rules.
An object type created by a connected app is badged Managed by that app. Integration-owned definitions are locked and CSV import is switched off for the schema. Records remain editable, but a later sync can overwrite fields the integration owns. Keep your campaign-specific fields separate from the upstream system's fields.
Work with your objects
Objects live under Records in the top navigation, listed by the slug of each type. From there you can:
- Search the list, and use Select Columns to pick which fields the table shows. The choice is remembered per type.
- Click a row to open the object. Edits save as you type.
- Tick rows to select them, then tag or delete them all at once.
Deleting is permanent. The deletion operation can continue while related event and derived data are removed, and workspace processing can be gated during cleanup. Wait for completion. Schema deletion can also be blocked by dependencies; replace those references before retrying.
Keep record state and event history distinct
Update the object when its current state changes: a subscription becomes canceled or an order is refunded. Send a separate event when the occurrence itself matters to automation. For profile calculations, attach the event's explicit objectId; an externalId inside its custom payload does not establish that subject link.
Objects can receive scheduled evaluated attributes, such as the latest observed usage of an account, as well as evaluated relationships. Both require expansion when an email or workflow needs their values. A missing published calculation is not equivalent to a measured zero.
Put objects to work
An object sitting in a table does nothing on its own. It earns its place the moment something reads it.
- Add an evaluated attribute to your contacts so each contact points at the objects that belong to them: "the company this person works for", "the last three things they bought".
- Pull those objects into an email with Liquid, or describe the result you want and let Adaptyle write it per recipient. An email has to ask for related records before it can use them: see attribute expansion.
- In a workflow, start a run with a Record Created or Updated step on an object type, look objects up mid-run with Find Records, or write back with Create or Update Records.