Object Type is a user attribute type that allows you to store a whole real-world entity as one connected attribute instead of scattering it across separate, unrelated attributes.
In real-life use cases, the things you care about are rarely a single value. They are entities made of several fields that only mean something together:
An order with its total, currency, status and shipping address
A subscription with its plan, status and renewal date
A booking with its reference, destination and lead passenger
A membership with its tier, join date and points
With flat attributes, each of those fields becomes its own standalone attribute and the link between them is lost. For example, membership_name, membership_status, and membership_renewal_date end up as three attributes with nothing connecting them. With Object Type, all of them live inside one object, under one attribute.
Object keys can also contain sub-object keys, and those can contain one further level, so a structure such as last_order.address.city is stored as it is. This keeps the relationships inside your data intact and makes the whole entity usable in segmentation, personalization, expressions, and export.
How Object Type Attributes Work
Object Type attributes follow the same principles as Array of Objects attributes, with two important differences: an object attribute holds exactly one object, not a list, and it supports three levels of nesting instead of two.
Structure is defined in the panel first
The object attribute and its object keys, sub-object keys and secondary sub-object keys must be created in the panel before data is sent. Auto-detection from incoming traffic is not supported. This keeps ingestion predictable and guarantees that every stored object follows a known schema.
Only registered keys are accepted
Object data must be sent through the dedicated object_attributes.custom field. Keys that are not registered in the panel are dropped during ingestion. Sending an object through the plain attributes field is rejected with an explicit error, because attributes accepts flat scalar values only.
Updates deep-merge
A payload that carries a subset of sub-keys updates only those sub-keys and leaves the rest of the object untouched, so you never have to re-send the whole object to change one field. This follows RFC 7386 merge-patch semantics, with "<null>" as the sentinel that clears a single sub-key.
One bad sub-key does not fail the payload
A sub-key that fails validation is dropped on its own. The rest of the object is still ingested, and the drop is recorded so it can be surfaced per field in the Onboarding Center rather than disappearing silently.
Data becomes segmentable in near real time
Object attributes follow the same availability behavior as flat attributes. Data is typically available for segmentation within seconds of ingestion.
Example Use Case: Last Order
Business Scenario
A retail partner migrating wants to:
Store the customer's last order as one attribute instead of six separate ones
Keep the order's total, currency, status and shipping address connected to each other
Segment customers whose last order shipped, was over 50, and went to a specific city
Personalize the message with a field from that same order
Before you begin
To follow this article end to end, make sure you have:
Access to the Attributes and Events page in the InOne panel, with permission to create custom attributes.
Your partner name and request token for the Insider One APIs. For more information, see the API Authentication article.
At least one free Object Type attribute slot on your panel. Each panel supports 20 Object Type attributes.
Note: Object Type is available on custom attributes only. Default attributes currently cannot use the Object data type.
Step 1. Create the Object Type Attribute
Before you can send and activate structured data, define the object attribute in the Attributes and Events section. Object attributes cannot be used in ingestion or segmentation until they are registered.
Navigate to Audience > Attributes and Events, open the Attributes tab, and click Create. The Create Custom Attribute drawer opens, where you set a system name and a display name that appears on the listing pages.
In the drawer:
Enter the Attribute System Name and the Attribute Display Name.
Select Object as the Data Type.
Add your object keys.
Set the PII, segmentation, tag, and note options as needed.
Click Create Attribute.
A last_order object attribute, for example, holds these keys:
Key Name | Type |
total | Number |
currency | String |
status | String |
ordered_at | Date |
is_gift | Boolean |
address | Object |
The Data Type selector is searchable and offers: Array of Objects, Boolean, Date, Number, Number Array, Object, String, String Array and URL.
When Object is selected, an Object Key section appears below the Data Type field, and the drawer grows as keys are added.
The full drawer, top to bottom, is:
Attribute System Name and Attribute Display Name
Data Type
One or more Object Key blocks, followed by + Add Object Key
Mark as Personally Identifiable Information (PII)
Use in Segmentation
Tags
Notes
Cancel and Create Attribute
Object Keys
Each Object Key block contains:
Object Key Name
Data Type
Sample of Data (optional)
Mark as Personally Identifiable Information (PII)
+ Add Sub-Object Key and Delete Object Key
Use + Add Object Key below the last block to add another key.
PII is configured per key as well as at attribute level, and the checkbox is available at every level, so a single object can mix PII and non-PII fields under the existing UCD PII policy. For example, booking.lead_passenger.name can be marked as PII while booking.destination is not.
Use in Segmentation controls whether the attribute is available in the segment builder. It is set at attribute level, not per key.
Supported Data Types
Object keys support the following data types:
Data Type | Description | Order Example |
String | Text values | status: "shipped" |
Number | Numeric values | total: 2499 |
Date | ISO-8601 datetime | ordered_at: "2026-04-01T14:30:00Z" |
Boolean | True/False values | is_gift: true |
URL | Valid web link | invoice_url: "https://cdn.example.com/inv.pdf" |
String Array | List of text values | tags: ["sale", "new"] |
Number Array | List of numeric values | sizes: [38, 39, 40] |
Object | Nested structured object | address: { city: "Istanbul", country: "TR" } |
Object-Type Keys and Nesting
If you select Object as the data type for an object key:
A Sub-Object Keys section appears under that key, with its own Sub-Object Key Name, Data Type, Sample of Data and Mark as PII fields, plus a delete action
+ Add Sub-Object Key adds further sub-keys under the same object key
If a sub-object key is itself typed as Object, a Secondary Sub-Object Keys section appears under it, added with + Add 2nd Level Sub-Object Key
The three levels are named as follows in the panel: Object Key (level 1), Sub-Object Key (level 2) and Secondary Sub-Object Key (level 3), which gives you three addressable levels:
last_order (root object attribute)
├─ total L1
├─ status L1
└─ address L1 (object)
├─ city L2
└─ geo L2 (object)
├─ latitude L3 <- deepest
└─ longitude L3 <- deepestIn this structure, address.geo.latitude sits at level 3 and uses the full allowance. A fourth object inside geo is rejected, and an array of objects currently cannot be used as a sub-key. Keys are stored as dot paths, for example address.geo.latitude.
Naming Rules
Object Key and Sub-Object Key names must start with a lowercase letter and can contain letters, numbers and underscores.
Spaces are automatically converted to underscores and names are lowercased while typing (for example, Unit Price becomes unit_price).
Names must be at least 3 characters.
An object key name cannot be the same as another object key name in the same attribute. It can be the same as an object key in a different attribute.
A sub-object key name cannot be the same as another sub-object key name in the same attribute. It can be the same as a sub-object key in a different attribute.
An object key and a sub-object key can share the same name under the same attribute.
action and value are reserved and cannot be used as key names, because they are used to detect the update envelope during ingestion.
Limit Behavior
When you reach a limit, the relevant option is disabled and a tooltip explains why:
Condition | Behavior |
Panel has reached the object attribute limit | The Object option is disabled in the Data Type list with the tooltip "Object Limit Reached — You have already added the maximum of 20 of Objects attributes." |
Panel has reached the total custom parameter limit | All data types are disabled with the tooltip "Custom Parameters Limit Reached — You have already added the maximum of [X] Custom Parameters." |
Panel has reached the Array of Objects limit but not the object limit | Only Array of Objects is disabled, with "Array of Objects Limit Reached — You have already added the maximum of 20 Array of Objects attributes." Object remains selectable. |
Attribute has reached the key limit | + Add Object Key and + Add Sub-Object Key are disabled with the tooltip "You have already added the maximum of 50 Object and Sub-Object Keys. Remove one or more of them to add new ones." |
Default and Configurable Limits
Limit | Default | Configurable |
Sub-keys per object, counted across all levels | 20 | Yes, up to 50, raised per partner |
Object type attributes per panel | 20 | Not configurable at launch |
Nesting levels | 3 | Not configurable |
String length per value | 500 characters | Not configurable |
Payload size per request | 5 MB | Not configurable |
The Object Type limit is tracked separately from the Array of Objects limit and from the general Custom Attributes limit, so registering an object attribute does not consume an Array of Objects slot. You can follow all three in the Key Metrics section at the top of the Attributes and Events page, where Array of Objects and Object each appear as their own sub-metric under Custom Attributes, for example Object 3 / 20.
Edit an Object Type Attribute
After you create an object attribute, its structure is locked. The edit drawer reuses the create drawer, so the same fields and validations apply, with parts of it disabled.
Editable | Not Editable |
Attribute Display Name | Attribute System Name |
Sample of Data, at every level | Attribute Data Type |
Adding new Object Keys | Existing Object Key names |
Adding new Sub-Object Keys and Secondary Sub-Object Keys | Existing Sub-Object Key names |
Mark as PII | Existing key data types |
Tags, Notes | Deleting existing keys |
Newly added keys follow the same rules and validations as the create flow, including the total key limit.
When the attribute is already in use
If the attribute is used anywhere, a further set of fields locks: Attribute System Name, Data Type, Object Key Data Type, Delete Object Key, Delete Sub-Object Key, and Use in Segmentation. If it is used in a campaign surface, the drawer becomes read-only.
Converting an existing attribute is not possible
The Object data type can only be selected when you create a new attribute. On an attribute of another type, the option is disabled with the tooltip "Data Type Unavailable. Object data type can only be selected when creating a new attribute."
Step 2. Send Object Data
After you define the attribute, start sending data. Object data must be sent inside the dedicated object_attributes.custom field, which is the only accepted location:
POST /api/user/v1/upsert
Keep sending flat attributes in attributes. Flat and object attributes can coexist in the same payload. An object sent inside attributes is rejected with an explicit error.
Create the object (Upsert API)
Sample request:
curl --location --request POST 'https://unification.useinsider.com/api/user/v1/upsert' \
--header 'X-PARTNER-NAME: PARTNER_NAME_GOES_HERE' \
--header 'X-REQUEST-TOKEN: TOKEN_GOES_HERE' \
--header 'Content-Type: application/json' \
--data-raw '{
"users": [
{
"insider_id": "u-12345",
"object_attributes": {
"custom": {
"last_order": {
"total": 2499,
"currency": "TRY",
"status": "shipped",
"address": { "city": "Istanbul", "country": "TR" }
}
}
}
}
]
}'Sample response:
{
"data": {
"successful": {
"count": 1
},
"fail": {}
}
}Nested sub-keys (3 levels)
A sub-key typed as Object carries its own nested object, up to three levels in total:
"object_attributes": {
"custom": {
"last_order": {
"total": 2499,
"address": {
"city": "Istanbul",
"geo": { "latitude": 41.0082, "longitude": 28.9784 }
}
}
}
}Partial update (deep-merge)
Sending a subset of sub-keys updates only those sub-keys. Everything else in the stored object is preserved. Only last_order.status changes here:
{
"users": [
{
"insider_id": "u-12345",
"object_attributes": {
"custom": {
"last_order": { "status": "delivered" }
}
}
}
]
}If you need to overwrite the whole object rather than merge into it, use the action envelope form:
"last_order": { "action": "replace", "value": { "total": 199, "status": "pending" } }The envelope supports merge (identical to the bare form), replace (whole-object set) and remove. add is rejected, because an object attribute holds exactly one object and has no array semantics.
Clear a sub-key and clearing the object
Clear a single sub-key with the "<null>" sentinel. Here last_order.currency is emptied and the rest of the object is preserved:
{
"delete_null": true,
"users": [
{
"insider_id": "u-12345",
"object_attributes": {
"custom": {
"last_order": { "currency": "<null>" }
}
}
}
]
}Clear the whole object value for a user. The registered schema stays in place:
{
"partner": "acme",
"source": "all",
"users": [
{
"insider_id": "u-12345",
"delete": ["last_order"]
}
]
}How Values Are Handled
Date values are normalized to UTC on ingestion. Send them in ISO 8601 format, for example "2026-04-01T14:30:00Z".
String values are stored as sent, including case. Comparisons in segmentation are case-sensitive.
Nested objects are stored against the dot path defined in the panel, for example address.geo.latitude.
Array values inside an object are replaced wholesale on update, not appended.
Multiple object attributes can be sent in the same payload, for example last_order and account together.
Reserved names (action, value, and internal field names) cannot be used as keys and are rejected.
Ingestion Behavior
Ingestion separates two classes of problems. Structural violations fail the record, and schema mismatches drop only the offending sub-key.
Structural violations, rejected
Input | Behavior |
Nesting deeper than 3 levels | Rejected, with the path named in the response |
An array of objects used as a sub-key | Rejected |
An object sent inside attributes instead of object_attributes | Rejected with an explicit error |
A string value longer than 500 characters | Rejected |
A reserved name used as a key | Rejected |
"action": "add" in the envelope form | Rejected |
Schema mismatches, the bad sub-key is dropped, the rest is stored
Input | Behavior |
Sub-keys that are not defined in the attribute schema | Only the keys defined in the schema are stored. Undefined keys are dropped. |
A value whose type does not match the key's data type | That key is dropped. The rest of the object is stored. |
An attribute that is not registered in the panel | Not stored. Register the attribute first, then send the data. |
A dropped sub-key is never silent. Each drop is recorded per field so it can be surfaced in the Onboarding Center, where an integration developer can see exactly which field was rejected and why.
Error Message Example
Nesting deeper than three levels
Registering a key deeper than three levels fails at schema creation with an HTTP 400 response. At ingestion, the request returns HTTP 200 with a per-path error in the body:
{
"data": {
"successful": {},
"fail": {
"count": 1,
"errors": {
"users.0.object_attributes.custom.last_order.address.geo.coords.lat": [
"nested object depth cannot exceed 3 levels"
]
}
}
}
}Step 3. View Object Type Attributes in the User Profile
After you send the data, confirm that the object is stored correctly from the InOne panel.
Open the User Profile and click View All User Attributes in the Basic Information section. The All User Attributes panel opens, with a tab per attribute family: Array of Objects Attributes, Object Attributes, Expressions and so on.
On the Object Attributes tab, each attribute is listed by name with its keys underneath:
Level 1: object keys and their values appear directly under the attribute name.
Level 2: an object-typed key appears as an expandable row that opens to reveal its sub-object keys.
Level 3: a sub-object key that is itself an object expands again to reveal its secondary sub-object keys.
Profile reads return the object in its original nested structure with all three levels preserved, so what you see here matches what you sent. Use this view to verify the structure and the values stored on each user.
Step 4. Use Object Type Attributes in Segmentation
Once the object is ingested, its keys are available directly in the segment builder.
Build the condition
Navigate to Audience > Dynamic Segments > New Segment and add an Attributes condition. The row has four parts:
Segment: the object attribute, for example Pets
Object Keys: the key inside the object
Operator
Value
Select the key
The Object Keys dropdown is searchable and cascading. Selecting an object key that is typed as Object opens a submenu with its sub-object keys, and a sub-object key that is itself an object opens one more submenu with its secondary sub-object keys.
You navigate the structure the same way you defined it, and the selected key is labeled in the field: Sub-Object Key for a level 2 selection, and 2nd Sub-Object Key for a level 3 selection.
Step 5. Export
Raw Export V2
Select the whole object, which exports as structured JSON preserving all three levels, or select individual keys by dot path, for example last_order.currency and last_order.address.city. Exported key columns follow the flatten convention, so last_order.address.city becomes last_order_address_city. Requested paths are validated against the registered schema, and an unknown path returns a per-column error. See Export Raw User Data V2 for details.
S3 export
The object is exported as structured JSON with all levels preserved.
Filtering on object keys in export uses the same segmentation conditions described in Step 4.
Limitations
Structure
Each panel can have a maximum of 20 object type attributes, tracked separately from the Array of Objects and general Custom Attributes limits.
Each object can contain up to 20 sub-keys by default, raisable per partner up to 100. The count is combined across all levels.
A maximum of 3 nesting levels is supported. Anything deeper is rejected, not silently truncated.
An array of objects cannot be used as a sub-key. Object-type keys are allowed, but a collection inside an object is out of scope for this release.
String values cannot exceed 500 characters.
Payload size is limited to 5 MB per request.
action and value are reserved and cannot be used as key names.
Lifecycle
Object attributes must be registered in the panel before ingestion. Auto-detection from incoming traffic is not supported.
Object key and sub-object key names and data types cannot be renamed or deleted after creation. New keys can be appended.
Object data can only be sent through object_attributes.custom. An object sent inside attributes is rejected.
The Object data type can only be chosen when creating a new attribute, never by converting an existing one.
Use Cases
Retail and ecommerce: order context
A single order carries a total, a currency, a status, and a shipping address that only mean something together.
Why Object Type helps
Keep the whole order in one attribute instead of six.
Preserve the relationship between total, status, and destination.
Segment on combinations inside the same order.
Example campaigns
Target customers whose last order shipped, was above a value you set, and went to a given city.
Personalize a delivery message with the order status and destination.
Compute net order value from total minus discount and use it for a high-value segment.
Subscription and telco: plan and renewal
A subscription is a plan, a status, and a renewal date that belong together.
Why Object Type helps
Store plan, status, and renewal as one entity.
Act on the renewal without maintaining three separate attributes.
Personalize with the plan name from the same record.
Example campaigns
Target active subscribers whose renewal falls within the next seven days.
Promote an upgrade based on the current plan.
Suppress win-back messaging for customers who already renewed.
Travel and airlines: booking context
One booking carries a reference, a status, a destination, and a lead passenger with their own details.
Why Object Type helps
Keep booking and passenger details connected, including the nested passenger object.
Segment on destination and personalize with the passenger name.
Model the second and third level naturally, for example booking.lead_passenger.seat_pref.
Example campaigns
Greet the lead passenger by name in a pre-flight message.
Target travelers flying to a given destination who have not selected a seat.
Promote extra baggage based on the fare type in the same booking.
Insurance: policy records
A policy has a type, a coverage level, a premium, and an expiry date.
Why Object Type helps
Capture the policy as one entity.
Keep type, coverage, and expiry connected.
Segment on combinations within the same policy.
Example campaigns
Target customers with a policy expiring in the next 30 days above a coverage threshold.
Cross-sell based on the policy type held.
Personalize a renewal notice with the premium and expiry from the same record.
Pet and specialty retail: profile records
A pet profile carries a name, a breed, a birth date, and a food plan.
Why Object Type helps
Store the whole profile as one attribute rather than four.
Personalize with the pet name and segment on the food plan together.
Keep the profile readable on the user profile page.
Example campaigns
Target owners whose pet food plan is due for a refill.
Personalize with the pet name in a birthday campaign.
Segment by breed and age band from the same profile.
FAQ
Object Type compared to Array of Objects
Q: What is the difference between an Object Type attribute and an Array of Objects attribute?
A: An Object Type attribute stores exactly one structured record, such as the last order or the current subscription. An Array of Objects attribute stores many structured records under one attribute, such as every subscription a customer has ever held.
Two other differences matter in practice. Object Type supports three levels of nesting against Array of Objects' two, and Object Type keys can be used in expressions, which Array of Objects sub-keys cannot.
Q: Which one should I use?
A: If the entity is singular by nature, such as the last order, the current subscription, or the account, use Object Type. If you need a collection, such as all orders, all policies, or all pets, use Array of Objects.
If you need both, for example an order and its line items, model the order as an Object Type attribute, keep the line items in an Array of Objects attribute, and relate the two in segmentation. Array of objects as a sub-key is currently unavailable.
Q: Does registering an object attribute use up my Array of Objects slots?
A: No. Object Type attributes have their own dedicated pool of 20, independent of the 20 Array of Objects slots and of the general Custom Attributes limit.
Setup and ingestion
Q: Do I have to create the structure before sending data?
A: Yes. Define the object attribute and its keys in the panel before ingestion. Keys that are not registered are dropped, and an attribute that is not registered is not stored at all.
Q: Where do I put the object in the payload?
A: Inside object_attributes.custom, next to attributes. This is the only accepted location. An object placed inside attributes is rejected, because attributes accepts flat scalar values only.
Q: If I send only one field, does it overwrite the whole object?
A: No. Updates deep-merge by default. A payload carrying a subset of keys updates only those keys and leaves the rest untouched. To overwrite the whole object deliberately, use the "action": "replace" envelope form.
Q: How do I clear a single field without clearing the object?
A: Send that key with the "<null>" sentinel and "delete_null": true. The key is emptied and every other key in the object is preserved.
Q: How do I clear the whole object?
A: Send the attribute name in the delete array. The stored value is cleared and the registered schema stays in place, so you can start sending data again without re-creating the attribute.
Q: What happens if I send keys that are not defined in the panel?
A: Only the keys defined in the schema are stored. Undefined keys are dropped, the rest of the object is ingested, and the drop is recorded per field so you can review it in the Onboarding Center.
Editing and limits
Q: Can I rename or delete keys after creation?
A: No. Object key and sub-object key names and data types are fixed after creation. You can append new keys, including new sub-object keys under an existing object-type key. The display name, sample data, and PII flag stay editable.
Q: Why can I not edit my attribute at all?
A: Because it is in use. When the attribute is used anywhere, the fields that would change its meaning lock: system name, data type, key data types, the delete actions, and Use in Segmentation. When it is used in Web Templates, Single Mobile Campaigns, or Dynamic Content, the whole drawer becomes read-only, and the edit screen lists every campaign holding it with its status and product so you know what to stop first.
Q: Can I convert an existing attribute to Object?
A: No. The Object data type can only be chosen when creating a new attribute. On an existing attribute of another type the option is disabled, with the tooltip "Object data type can only be selected when creating a new attribute."
Q: How deep can I nest?
A: Three levels: object key, sub-object key, and secondary sub-object key. A fourth level is rejected. An array of objects currently cannot be placed inside an object.
Q: What are the system limits?
Limit | Value |
Object type attributes per panel | 20 |
Sub-keys per object | 20 by default, raisable to 100 |
Nesting levels | 3 |
String length per value | 500 characters |
Payload size per request | 5 MB |
Q: Can the limits be raised?
A: The sub-key limit is configured per customer and can be raised by the Insider One team on request. The attribute count per panel and the nesting depth are fixed in this release.
Activation
Q: How are multiple conditions evaluated in segmentation?
A: They are combined with AND and evaluated against the same stored object. Because an object attribute holds exactly one object, no ambiguity arises about which record matched, unlike Array of Objects where conditions must be satisfied within a single object of the array.
Q: Can I use object keys in campaign personalization?
A: Yes. Object keys are available as dynamic content with a fallback, and they can also feed expressions whose result is then used in segments and messages.
Q: Can I trigger a journey when an object field changes?
A: Hook triggers and filters on object keys are currently unavailable.
Q: Can I export object data?
A: Yes. Raw Export V2 supports selecting the whole object as structured JSON or selecting individual keys by dot path, and S3 export preserves the full structure.
Next steps
Object Type gives you one attribute per real-world entity, three addressable levels of structure, and a single dot path that works the same way across segmentation, personalization, expressions, and export. Register the attribute first, send data through object_attributes.custom, and verify the result on the user profile before you build campaigns on it.