Personalization Migration Guide#

To make it easier for sellers with personalizable listings to collect the information they need from buyers and more efficiently process personalizable orders, we have replaced the single free-text personalization field with an architecture that supports multiple, typed personalization inputs: text inputs, dropdowns, and file upload questions. More information about the reasoning behind this project can be found in the GitHub announcement.

info

What changed

  • Personalization is now managed through a dedicated data structure and a suite of personalization-specific endpoints (getListingPersonalization, updateListingPersonalization, and deleteListingPersonalization).
  • Listings support up to 5 personalization questions across 3 question types: text input, dropdown, and file upload.
  • The legacy personalization fields (personalization_is_required, personalization_char_count_max, and personalization_instructions) have been deprecated. Listing create/update requests that include these fields will return an error, and they are no longer returned when reading listing data.

For detailed examples of every request and response described here, see the Examples page.

Required changes#

To ensure your integration is compatible with personalization, you must make the following changes.

If you read personalization data on listings:#

  • Update your integration to use the new personalization data structure (details below).
  • Fetch listing personalization data via the new getListingPersonalization endpoint, or by calling one of getListingsByShop, getListing, or getListingsByListingIds with personalization in the includes query param.
  • Your integration must correctly display multiple questions across all three question types (text input, dropdown, and file upload).
  • The is_personalizable property will continue to be returned from the current listing endpoints.

If you read personalization data on transactions:#

  • Personalization data continues to be returned in the transaction variations array in the existing format. If your integration relies on the formatted_name being "Personalization" or on there being a single item with property_id: 54, it must be updated (see Reading transaction personalization data).

If you write personalization data on listings:#

  • Update your integration to use the new personalization POST and DELETE endpoints (updateListingPersonalization and deleteListingPersonalization). Requests to the POST endpoint fully replace the existing personalization data on the listing.
  • Stop sending legacy personalization fields on listing create and update requests.
  • To write multiple questions and/or new question types, follow the constraints in Writing listing personalization data.
tip

How to test: Use your normal process and be sure to follow these guidelines.

For guidance on how personalization works in Etsyweb, see the Help Center article: How to Offer Personalized Listings.

Reading listing personalization data#

Listing personalization data can be fetched through the dedicated GET endpoint or through the listing endpoints that return associations.

We are introducing a 120 character limit on the instructions field. Existing instructions values that exceed this limit are still returned in full by GET requests and are not automatically truncated. However, any update to these questions via a POST request must comply with the 120 character limit.

Through the dedicated personalization GET endpoint#

The getListingPersonalization endpoint (GET https://api.etsy.com/v3/application/listings/{listing_id}/personalization) fetches personalization data by listing_id. It returns a personalization_questions array. If the listing has no personalization configured, the array is empty.

The question data structure supports all question types:

{
"personalization_questions": [
{
"question_id": int,
"question_type": ENUM, // "text_input", "dropdown", "unlabeled_upload", "labeled_upload"
"question_text": string,
"instructions": string, // only applicable to text_input and upload questions
"required": bool,
"max_allowed_characters": int, // only applicable to text_input questions
"max_allowed_files": int, // only applicable to upload questions
"options": [ // applicable for dropdowns and labeled_upload questions
{
"option_id": int,
"label": string
}
]
}
]
}

Via endpoints that return listings with associations#

You can retrieve the personalization data for a listing from the following endpoints by appending the ?includes=personalization query param:

The response body includes a personalization key containing a possibly empty personalization_questions array. The is_personalizable property continues to be returned at the base listing level:

{
"is_personalizable": bool,
"personalization": {
"personalization_questions": [
{
"question_id": int,
"question_type": ENUM,
"question_text": string,
"instructions": string,
"required": bool,
"max_allowed_characters": int,
"max_allowed_files": int,
"options": [
{
"option_id": int,
"label": string
}
]
}
]
}
...
}
note

The legacy fields (personalization_is_required, personalization_char_count_max, and personalization_instructions) are no longer returned by these endpoints.

Reading transaction personalization data#

Personalization data for a transaction is returned (if present) as part of the variations array on a transaction object:

{
... // other transaction data
"variations": [
... // other variation data
{
"formatted_name": "Personalization",
"formatted_value": string,
"property_id": 54,
"value_id": int|null
}
]
}

Transaction personalization continues to be returned in this format, but be advised of the following changes:

  • The formatted_name may be a seller-configured value, not necessarily "Personalization".
  • There may be multiple objects with property_id: 54.
  • For file uploads, the formatted_value will be a URL.

Writing listing personalization data#

The updateListingPersonalization endpoint (POST https://api.etsy.com/v3/application/shops/{shop_id}/listings/{listing_id}/personalization) creates or updates personalization data for a listing.

note

This endpoint fully replaces the existing personalization data on the listing with the data you send. To create personalization you must first have an existing listing; if you don't have one, create it with createDraftListing first.

The endpoint accepts an array of up to 5 personalization_questions and supports all question types:

{
"personalization_questions": [
{
"question_id": int,
"question_type": ENUM, // "text_input", "dropdown", "unlabeled_upload", "labeled_upload"
"question_text": string,
"instructions": string, // only allowed for text_input and upload questions, limited to 120 characters
"required": bool,
"max_allowed_characters": int, // required for text_input questions
"max_allowed_files": int, // required for upload questions
"options": [ // required for dropdowns and labeled_upload questions
{
"label": string
}
]
},
...
]
}
warning

When you write multiple questions and new question types, you must also append ?supports_multiple_personalization_questions=true when calling this endpoint. This lets us track adoption and prevents inadvertent overwrites of seller data from non-updated apps. Without this query param, attempts to write data that would delete previously configured personalization questions will fail with a 409 Conflict error.

Adding the param without updating your application can lead to deleting data provided by the seller on Etsyweb.

Please note the following constraints:

  • The personalization_questions array must contain between 1 and 5 elements.
  • At most one upload-type question (either unlabeled_upload or labeled_upload) may be sent per listing.

There are also field-level constraints:

  • question_text
    • Must be between 1 and 45 characters
    • Must begin with a letter or number
    • Must not contain more than one word starting with 3+ capitalized letters
  • instructions
    • Must be empty or null for dropdowns
    • Optional for the other question types
    • Must not exceed 120 characters when provided (requests will fail validation otherwise)
    • Must begin with a letter or number
    • Must not contain more than one word starting with 3+ capitalized letters
  • max_allowed_characters
    • Required for text_input questions; not allowed for other question types
    • Must be between 1 and 1024
  • max_allowed_files
    • Required for upload questions (either labeled or unlabeled); not allowed for other question types
    • Must be between 1 and 10
    • For labeled_upload questions, max_allowed_files must be 2 or more
  • options
    • Required for dropdown and labeled_upload questions; not allowed for other question types
    • For dropdowns:
      • Must contain 1 - 30 options
      • Each label must be 1 - 20 characters
      • Labels must be unique within the question
    • For labeled uploads:
      • Length must equal max_allowed_files
      • Each label must be 1 - 45 characters
  • question_id
    • Optional, but encouraged if you are updating or adding to existing personalization on a listing (example)

Deleting personalization from a listing#

The deleteListingPersonalization endpoint (DELETE https://api.etsy.com/v3/application/shops/{shop_id}/listings/{listing_id}/personalization) turns off personalization for a listing and removes the associated data.

The is_personalizable property will be set to false on the main listing record as a result of this action.

For detailed examples of each of these operations, see the Examples page.