Google Wallet offers powerful tools to customize the appearance and layout of any pass, from Event Tickets and Boarding Passes to Loyalty and Gift Cards. This guide provides a comprehensive overview of how you can tailor the user experience by defining the structure of the card and displaying dynamic, user-specific information.

Before you begin, be sure to consult the specific REST API reference documentation for your pass type to see a full list of available fields.

- [Loyalty](https://developers.google.com/wallet/reference/rest/v1/loyaltyclass.md.txt)
- [Offer](https://developers.google.com/wallet/reference/rest/v1/offerclass.md.txt)
- [Gift Card](https://developers.google.com/wallet/reference/rest/v1/giftcardclass.md.txt)
- [Event Ticket](https://developers.google.com/wallet/reference/rest/v1/eventticketclass.md.txt)
- [Boarding Pass](https://developers.google.com/wallet/reference/rest/v1/flightclass.md.txt)
- [QR Tickets](http://developers.google.com/wallet/reference/rest/v1/transitclass.md.txt)

## The Foundation: `cardTemplateOverride`

The primary tool for customizing the layout of a pass is the `classTemplateInfo.cardTemplateOverride` object, which you define in the pass's `Class` resource (e.g., `EventTicketClass`, `LoyaltyClass`). This object lets you to structure the pass by defining rows and the items within them, giving you control over how information is presented.

You can reference data from both the `Class` resource (for information shared across all users) and the `Object` resource (for user-specific details).

## 1. Customizing with Predefined Wallet Fields

Predefined fields are the standard properties available in the Google Wallet API for a specific pass type. These fields have specific names and are rendered by Wallet in a consistent way. Examples include a barcode, an event name, a flight number, or a gift card balance.

By referencing the `fieldPath` of these predefined fields, you can arrange them anywhere on your pass.

**Example: Displaying Barcode and Pass-Specific Details**

This pass example has a "Top row" and 3 data fields inside the 2nd row. The first item displays the user's specific values from the `Object` like points or seat number specific to the user. The second item displays the details from the `Class` like an event name or loyalty program tier, and the third again displays the user's specific values from the `Object` like secondary point or section / coach number.

![Predefined Fields](https://developers.google.com/static/wallet/images/passes/templates/card_customization_predefined.png "Pass with predefined fields")

**Class Definition:**

```json
...
"classTemplateInfo": {
      "cardTemplateOverride": {
        "cardRowTemplateInfos": [
          {
            "twoItems": {
              "startItem": {
                "firstValue": {
                  "fields": [
                    {
                    "fieldPath": "object.accountName",
                    }
                  ]
                }
              },
              "endItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "object.secondaryLoyaltyPoints.label"
                    },
                    {
                      "fieldPath": "object.secondaryLoyaltyPoints.balance"
                    }
                  ]
                }
              }
            }
          },
          {
            "twoItems": {
              "startItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "object.loyaltyPoints.label"
                    },
                    {
                      "fieldPath": "object.loyaltyPoints.balance"
                    }
                  ]
                }
              },
              "endItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "class.rewardsTierLabel"
                    },
                    {
                      "fieldPath": "class.rewardsTier"
                    }
                  ]
                }
              }
            }
          },
        ]
      }
    }
...
"rewardsTier": "Gold",
"rewardsTierLabel": "Tier",
...
```

**Object Definition**

```json
...
"accountName": "Camille Walsh",
"loyaltyPoints": {
    "balance": {
        "string": "1500"
    },
    "label": "Points"
},
"secondaryLoyaltyPoints" : {
    "balance": {
        "money": {
            "micros" : "35050000",
            "currencyCode": "USD",
        }
    },
    "label": "Balance"
}
...
```

> [!NOTE]
> **Note:** The `fieldPath` value depends on the pass type. For example, to display an event name, you would use `"fieldPath": "class.eventName.defaultValue.value"`. Refer to the specific `Class` and `Object` reference documentation for a complete list of available fields.

### Format Date and Time Fields

For any date or time field in supported passes, you can specify a custom format using the `dateFormat` property. This lets you to control how the date is displayed on the pass, such as showing only the time, the full date and time, or just the date. If `dateFormat` is not specified, a default format will be used.

```json
"fields": [
  {
    "fieldPath": "object.validTimeInterval.start.date",
    "dateFormat": "DATE_ONLY"
  }
]
```

For a complete list of available formats, see the [`DateFormat` documentation](https://developers.google.com/wallet/reference/rest/v1/ClassTemplateInfo.md.txt#DateFormat).

## 2. Customizing with Developer-Defined Fields

For ultimate flexibility, Google Wallet lets you to create your own custom data fields using `textModulesData`. This is perfect for displaying unique information that doesn't fit into the predefined fields, such as custom short notes, member benefits, or location-specific details.

> [!IMPORTANT]
> **Important:** Before creating a custom field, always review the predefined fields in the reference documentation for your pass type. A standard field may already exist for your use case. Using predefined fields can significantly enhance the user experience by enabling intelligent features across Google surfaces like proactive notifications, updates on the Pixel home screen, and discoverability in Search---when users have granted the necessary permissions.

You define a `textModulesData` item with a unique `id` in the `Object` or `Class`, and then reference that `id` in the `cardTemplateOverride`.

### Structure Card Rows

You can design a pass with one, two, or three data items per pass, allowing you to organize information logically. There's no hard limit to the number of rows you can add, but for a clean user experience, consider what is most important to display on the card face.

- **Best Practice:** For supplementary information, use the [bottom section of the pass](https://developers.google.com/wallet/tickets/transit-passes/qr-code/use-cases/pass-customization.md.txt#content_in_the_bottom_section_of_the_pass) or other Wallet features like `messages`, `linksModuleData`, or `linkedOfferIds`. This keeps the main pass view uncluttered.

**Example: A Three-Item Row with Custom Data**

Create a row to display custom details. For a loyalty card, this could be points, tier, and balance. For an event ticket, it could be "Section," "Row," and "Seat."

![Custom and Predefined Fields](https://developers.google.com/static/wallet/images/passes/templates/card_customization_override.png "Pass with predefined and developer defined fields")

**Class Definition:**
The `cardTemplateOverride` references three unique IDs: `detail1`, `detail2`, and `detail3`.

```json
...
"classTemplateInfo": {
      "cardTemplateOverride": {
        "cardRowTemplateInfos": [
        {
            "twoItems": {
              "startItem": {
                "firstValue": {
                  "fields": [
                    {
                    "fieldPath": "object.accountName",
                    }
                  ]
                }
              },
              "endItem": {
                "firstValue": {
                  "fields": [
                    {
                     "fieldPath": "object.textModulesData['mem_since']",
                    }
                  ]
                }
              }
            }
          },
          {
            "twoItems": {
              "startItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "object.loyaltyPoints.label"
                    },
                    {
                      "fieldPath": "object.loyaltyPoints.balance"
                    }
                  ]
                }
              },
              "endItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "class.rewardsTierLabel"
                    },
                    {
                      "fieldPath": "class.rewardsTier"
                    }
                  ]
                }
              }
            }
          },
          {
            "twoItems": {
              "startItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "object.secondaryLoyaltyPoints.label"
                    },
                    {
                      "fieldPath": "object.secondaryLoyaltyPoints.balance"
                    }
                  ]
                }
              },
              "endItem": {
                "firstValue": {
                  "fields": [
                    {
                      "fieldPath": "object.textModulesData['visits']",
                    }
                  ]
                }
              }
            }
          },
        ]
      }
    }
...
"rewardsTier": "Gold",
"rewardsTierLabel": "Tier",
```

**Object Definition:**
The `Object` provides the data and corresponding IDs for each field.

```json
...
"accountName": "Camille Walsh",
"loyaltyPoints": {
    "balance": {
        "string": "1500"
    },
    "label": "Points"
},
"secondaryLoyaltyPoints" : {
    "balance": {
        "money": {
            "micros" : "28250000",
            "currencyCode": "USD",
        }
    },
    "label": "Balance"
},
"textModulesData": [
{
    "header": "Visits",
    "body": "17",
    "id": "visits"
  },
  {
    "header": "Member since",
    "body": "Mar 01, 2024",
    "id": "mem_since"
  },
]
...
```

### Class versus Object Data for Variations

You can combine class-level and object-level data to create dynamic, personalized passes. This is useful for creating different versions of the same pass.

- **Class-level `textModulesData`:** Use this for details that are the same for a group of users (e.g., a "Welcome to VIP" message for all VIP ticket holders).
- **Object-level `textModulesData`:** Use this for details specific to one user (e.g., "Jane, your seat has a restricted view").

**Example: Displaying Tier-Specific Passes**

You can create different `Class` resources for different pass variations, such as "General Admission" versus "VIP" for an event, or "Economy" versus "Business" for a flight. Each class can have a unique design (hero image, color) and default text.

|---|---|---|
| ![Member in the silver tier](https://developers.google.com/static/wallet/images/passes/templates/card_customization_silver.png) | ![Member upgraded to Gold](https://developers.google.com/static/wallet/images/passes/templates/card_customization_gold.png) | ![Member in the Diamond tier](https://developers.google.com/static/wallet/images/passes/templates/card_customization_diamond.png) |
| Member starting with Silver | Member upgraded to Gold | Another Member in Diamond Tier |

### Content in the bottom section of the pass

Fields from `linksModuleData`, `imageModulesData` are not rendered when
referenced in `cardTemplateOverride`. This content is automatically displayed
in the **bottom section of the pass**, providing users with better access
to customer service links, promotional images, terms and conditions, and other
supplementary information.

## 3. Beyond the Card Face: Other Template Overrides

The `classTemplateInfo` object offers more than just `cardTemplateOverride`. You can customize other parts of the Google Wallet experience to provide a richer and more intuitive presentation of your passes.

For full details on all available overrides, refer to the [`ClassTemplateInfo` reference documentation](https://developers.google.com/wallet/reference/rest/v1/ClassTemplateInfo.md.txt).

- **`listTemplateOverride`**: Customizes the row layout in the main list view of the Google Wallet app, allowing you to highlight the most important fields before a user even opens their pass.
- **`detailsTemplateOverride`**: Structures the rows and layout of the bottom section of the pass, giving you a flexible space for supplementary information, links, and text.
- **`cardBarcodeSectionDetails`**: Lets you customize the barcode section on the pass.