Point of Interest (POI) feed

Create and upload POI feeds

When creating and uploading POI feeds, follow these instructions:

  • Follow the spec described in the POI feed for POI data files. We recommend using unique POI data file names for each upload. Include a timestamp in the filename, for example, POI_1633621547.json.
  • Upload feeds to the local POI SFTP server daily as full refreshes.
  • You can find SFTP server details in the Configuration > Feeds section of the Partner Portal.

Selecting feed servers

Feed Specifications

Field Requirements

VssPoi

Represents a single Point of Interest (POI) entity e.g. a hotel or restaurant.

Field NameTypeRequirementDescription
poi_idstring

Required

Required. A string generated by the partner that identifies a POI.
nameobject
(Text)

Required

Required. The name of the POI.
telephonestring

The contact telephone number of the POI including its country and area codes, e.g. +14567891234.
urlstring

The url of the POI's public website. Note: This will be used just for matching purposes, not for display.
locationobject
(GeoCoordinates)

Required

Required. The location of the POI.
display_addressobject
(Text)

The address displayed on the UI.
imagesarray of object
(Image)

Images of the POI. Max number of images: 5.
ratingnumber

Average rating for the POI.
num_ratingsnumber

The number of contributing ratings for the rating field.
rating_scalenumber

The rating scale used for the rating field. If max rating is 5, then rating_scale is 5.
categoryenum
(Category)

Required

Required. Represents the category of the POI.
descriptionobject
(Text)

A description of the POI.
oneOf
(additional_data)

Required

Only one of the fields in this oneOf can be set.

Text

Represents a text with localizations.

Field NameTypeRequirementDescription
localizationsarray of object
(LocalizedString)

The localized strings.
default_localestring

The locale to use as the default language it must be present in the localizations.

LocalizedString

Represents a localized string.

Field NameTypeRequirementDescription
localestring

The text's language tag, such as "en", "en-US" or "sr-Latn".
textstring

The text in the specified locale.

GeoCoordinates

The Geo data of a location, including latitude, longitude, and address.

Field NameTypeRequirementDescription
latitudenumber

[-90, +90] degrees (inclusive). Required if longitude is set, otherwise nice to have.
longitudenumber

[-180, +180] degrees (inclusive). Required if latitude is set, otherwise nice to have.
oneOf
(addresses)

Required

Only one of the fields in this oneOf can be set.

PostalAddress

The postal address for the location.

Field NameTypeRequirementDescription
countrystring

Required

Required. The country, using ISO 3166-1 alpha-2 country code, e.g. "US".
localitystring

Required

Required. The locality/city, e.g. "Mountain View".
regionstring

The region/state/province, e.g. "CA". This field is only required in countries where region is commonly a part of the address. (optional)
postal_codestring

Required

Required. The postal code, e.g. "94043".
street_addressstring

Required

Required. The street address, e.g. "1600 Amphitheatre Pkwy".

Image

Represents an image of the Point of Interest (POI).

Field NameTypeRequirementDescription
urlstring

The url of the image. Google will crawl the media hosted at this URL. Max length: 2000.
alt_textobject
(Text)

The alternative text to be used for accessibility.

HotelData

Hotel specific feed data.

Field NameTypeRequirementDescription
hotel_star_classnumber

The official hotel class star value. Can be used in a label like "5-star hotel." This value is expected to be an integer between 1 and 5.
brand_idsarray of string

The brands that can display this hotel. If this field is empty, the hotel can be displayed under any of the brands associated with the feed.

LocalData

Establishment specific feed data.

Field NameTypeRequirementDescription
business_hoursobject
(BusinessHours)

The regular business hours of the establishment.
price_rangeobject
(PriceRange)

Price range of the services offered by the establishment.
establishment_categoryobject
(Text)

The type of establishment.
brand_landing_pagesarray of object
(BrandLandingPages)

The brand landing pages.

BusinessHours

Represents the time periods that this location is open for business. Holds a collection of [TimeRange][madden.vss_poi_feed.TimeRange] instances. Example: Open on Saturdays from 09:00-12:00 and 13:00-17:00: time_ranges { open_day: SATURDAY open_time: { hours: 9, minutes: 0 } close_day: SATURDAY close_time: { hours: 12, minutes: 0 } } time_rages { open_day: SATURDAY open_time: { hours: 13, minutes: 0 } close_day: SATURDAY close_time: { hours: 17, minutes: 0 } } Example: Open on Saturdays from 21:00 to Sunday 02:00: time_ranges { open_day: SATURDAY open_time: { hours: 21, minutes: 0 } close_day: SUNDAY close_time: { hours: 2, minutes: 0 } }

Field NameTypeRequirementDescription
time_rangesarray of object
(TimeRange)

A collection of times that this POI is open for business. Each period represents a range of hours when the POI is open during the week.

TimeRange

Represents a span of time that the POI is open, starting on the specified open day/time and closing on the specified close day/time. The closing time must occur after the opening time, for example later in the same day, or on a subsequent day.

Field NameTypeRequirementDescription
open_dayenum
(DayOfWeek)

The open day of the time range.
open_timeobject
(TimeOfDay)

The open time of the time range.
close_dayenum
(DayOfWeek)

The close day of the time range.
close_timeobject
(TimeOfDay)

The close time of the time range.

TimeOfDay

Field NameTypeRequirementDescription
hoursnumber

Hours of a day in 24 hour format. Must be greater than or equal to 0 and typically must be less than or equal to 23. An API may choose to allow the value "24:00:00" for scenarios like business closing time.
minutesnumber

Minutes of an hour. Must be greater than or equal to 0 and less than or equal to 59.
secondsnumber

Seconds of a minute. Must be greater than or equal to 0 and typically must be less than or equal to 59. An API may allow the value 60 if it allows leap-seconds.
nanosnumber

Fractions of seconds, in nanoseconds. Must be greater than or equal to 0 and less than or equal to 999,999,999.

PriceRange

Price range of the services offered by the POI.

Field NameTypeRequirementDescription
min_priceobject
(Money)

The minimum price of the services offered by the POI.
max_priceobject
(Money)

The maximum price of the services offered by the POI.

Money

Represents an amount of money with its currency type.

Field NameTypeRequirementDescription
currency_codestring

The three-letter currency code defined in ISO 4217.
unitsnumber

The whole units of the amount. For example if currencyCode is "USD", then 1 unit is one US dollar.
nanosnumber

Number of nano (10^-9) units of the amount. The value must be between -999,999,999 and +999,999,999 inclusive. If units is positive, nanos must be positive or zero. If units is zero, nanos can be positive, zero, or negative. If units is negative, nanos must be negative or zero. For example $-1.75 is represented as units=-1 and nanos=-750,000,000.

BrandLandingPages

The Localized brand landing pages for a single Point of Interest (POI).

Field NameTypeRequirementDescription
brand_idstring

The brand this configuration applies to.
localized_landing_pagesarray of object
(LocalizedLandingPage)

The localized landing pages. The url and locales fields values must be unique across all the localized landing pages.
default_urlstring

The default landing page url to be used when none of the localized landing pages matches the user's language.

LocalizedLandingPage

Localized landing page for the Point of Interest (POI).

Field NameTypeRequirementDescription
urlstring

The url of the landing page. Max length: 2000.
localesarray of string

Restricts this page to users with the specified language preference. Must contain language tags, such as "en", "en-US" or "sr-Latn".

Category

Represents the category of the POI. It should match the additional_data oneof field below.

NameDescription
UNKNOWN_CATEGORY
HOTEL
LOCAL

DayOfWeek

Represents a day of the week.

NameDescription
DAY_OF_WEEK_UNSPECIFIEDThe day of the week is unspecified.
MONDAYMonday
TUESDAYTuesday
WEDNESDAYWednesday
THURSDAYThursday
FRIDAYFriday
SATURDAYSaturday
SUNDAYSunday

additional_data

Required. Category specific fields. It should match the category field above.

Field NameTypeRequirementDescription
hotel_dataobject
(HotelData)

Mutally exclusive with local_data

Hotel specific fields.
local_dataobject
(LocalData)

Mutally exclusive with hotel_data

Local specific fields.

addresses

Required. Address for a location.

Field NameTypeRequirementDescription
addressobject
(PostalAddress)

Postal address of the location.
  • Format: Must be JPEG, PNG, or WebP.
  • Max File Size: Under 30 MB per image.
  • Max Dimensions: Less than 75 Megapixels total (width x height < 75,000,000).
  • URL Type: Direct path to the image asset (e.g., ends in .jpg).
  • Permissions: Ensure the hosting server allows access to Googlebot or Crawlers and has no robots.txt blocking the image directories.
  • Safe Search: Images must comply with Google's safe search policies.

Definitions

VssPoiFeed Definition

// Represents a Point of Interest (POI) data feed provided by a partner.
export message VssPoiFeed {
  // The POIs in the feed.
  repeated VssPoi data = 1;
}

VssPoi Definition

// Represents a single Point of Interest (POI) entity e.g. a hotel or
// restaurant.
export message VssPoi {
  // Required. A string generated by the partner that identifies a POI.
  string poi_id = 1;

  // The entity name, telephone, url and location are used to support
  // matching partner inventory with entities already present on Google.

  // Required. The name of the POI.
  Text name = 2;

  // The contact telephone number of the POI including its country and
  // area codes, e.g. +14567891234.
  string telephone = 3 [(datapol.semantic_type) = ST_PHONE_NUMBER];

  // The url of the POI's public website.
  // Note: This will be used just for matching purposes, not for display.
  string url = 4;

  // Required. The location of the POI.
  GeoCoordinates location = 5;

  // The address displayed on the UI.
  Text display_address = 17;

  // Images of the POI.
  // Max number of images: 5.
  repeated Image images = 6;

  // Average rating for the POI.
  float rating = 12;

  // The number of contributing ratings for the `rating` field.
  int64 num_ratings = 13;

  // The rating scale used for the `rating` field. If max rating is 5, then
  // rating_scale is 5.
  int32 rating_scale = 14;

  // Represents the category of the POI.
  // It should match the `additional_data` oneof field below.
  export enum Category {


    LOCAL = 4;
  }

  // Required. Represents the category of the POI.
  Category category = 9;

  // A description of the POI.
  Text description = 16;

  // Required. Category specific fields.
  // It should match the `category` field above.
  oneof additional_data {


    // Local specific fields.
    LocalData local_data = 15;
  }

}

Text Definition

// Represents a text with localizations.
message Text {
  // Represents a localized string.
  message LocalizedString {
    // The text's language tag, such as "en", "en-US" or "sr-Latn".
    string locale = 1;

    // The text in the specified locale.
    string text = 2;
  }

  // The localized strings.
  repeated LocalizedString localizations = 1;

  // The locale to use as the default language it must be present in the
  // localizations.
  string default_locale = 2;
}

GeoCoordinates Definition

// The Geo data of a location, including latitude, longitude, and address.
message GeoCoordinates {
  option (datapol.msg_semantic_type) = ST_LOCATION;

  // [-90, +90] degrees (inclusive).
  // Required if longitude is set, otherwise nice to have.
  double latitude = 1;

  // [-180, +180] degrees (inclusive).
  // Required if latitude is set, otherwise nice to have.
  double longitude = 2;

  // Required. Address for a location.
  oneof addresses {
    // Postal address of the location.
    PostalAddress address = 3;

  }
}

PostalAddress Definition

// The postal address for the location.
message PostalAddress {
  option (datapol.msg_semantic_type) = ST_LOCATION;

  // Required. The country, using ISO 3166-1 alpha-2 country code, e.g. "US".
  string country = 1;

  // Required. The locality/city, e.g. "Mountain View".
  string locality = 2;

  // The region/state/province, e.g. "CA". This field is only required in
  // countries where region is commonly a part of the address. (optional)
  string region = 3;

  // Required. The postal code, e.g. "94043".
  string postal_code = 4;

  // Required. The street address, e.g. "1600 Amphitheatre Pkwy".
  string street_address = 5;
}

Image Definition

// Represents an image of the Point of Interest (POI).
export message Image {
  // The url of the image. Google will crawl the media hosted at this URL.
  // Max length: 2000.
  string url = 1;

  // The alternative text to be used for accessibility.
  Text alt_text = 2;
}

LocalData Definition

// Establishment specific feed data.
message LocalData {
  // The regular business hours of the establishment.
  BusinessHours business_hours = 1;

  // Price range of the services offered by the establishment.
  PriceRange price_range = 2;

  // The type of establishment.
  Text establishment_category = 3;

  // The brand landing pages.
  repeated BrandLandingPages brand_landing_pages = 4;
}

BrandLandingPages Definition

// The Localized brand landing pages for a single Point of Interest (POI).
message BrandLandingPages {
  // The brand this configuration applies to.
  string brand_id = 1 [(datapol.semantic_type) = ST_PARTNER_ID];

  // Localized landing page for the Point of Interest (POI).
  message LocalizedLandingPage {

    // The url of the landing page.
    // Max length: 2000.
    string url = 1;

    // Restricts this page to users with the specified language preference.
    // Must contain language tags, such as "en", "en-US" or "sr-Latn".
    repeated string locales = 3;
  }

  // The localized landing pages.
  // The url and locales fields values must be unique across all the localized
  // landing pages.
  repeated LocalizedLandingPage localized_landing_pages = 2;

  // The default landing page url to be used when none of the localized
  // landing pages matches the user's language.
  string default_url = 3;
}

Samples

Point of Interest Feed

Filename: poi_1707240000.json

{
  "data": [
    {
      "poi_id": "test_restaurant_1",
      "name": {
        "localizations": [
          {
            "locale": "en",
            "text": "Tasty Bites Test Restaurant"
          }
        ],
        "default_locale": "en"
      },
      "telephone": "+1234567890",
      "url": "https://www.tastybitestest.com",
      "location": {
        "latitude": 37.422,
        "longitude": -122.084,
        "address": {
          "country": "US",
          "locality": "Mountain View",
          "postal_code": "94043",
          "street_address": "1600 Amphitheatre Pkwy"
        }
      },
      "display_address": {
        "localizations": [
          {
            "locale": "en",
            "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
          }
        ],
        "default_locale": "en"
      },
      "images": [
        {
          "url": "https://www.tastybitestest.com/images/interior.jpg",
          "alt_text": {
            "localizations": [
              {
                "locale": "en",
                "text": "Cozy dining area of Tasty Bites"
              }
            ],
            "default_locale": "en"
          }
        }
      ],
      "rating": 4.7,
      "num_ratings": 150,
      "rating_scale": 5,
      "category": "LOCAL",
      "description": {
        "localizations": [
          {
            "locale": "en",
            "text": "A mock restaurant for testing the POI feed ingestion."
          }
        ],
        "default_locale": "en"
      },
      "local_data": {
        "establishment_category": {
           "localizations": [
             {
               "locale": "en",
               "text": "Restaurant"
             }
           ],
           "default_locale": "en"
        },
        "price_range": {
          "min_price": {
            "currency_code": "USD",
            "units": 15,
            "nanos": 0
          },
          "max_price": {
            "currency_code": "USD",
            "units": 45,
            "nanos": 0
          }
        },
        "business_hours": {
          "time_ranges": [
            {
              "open_day": "MONDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "MONDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "TUESDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "TUESDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "WEDNESDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "WEDNESDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "THURSDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "THURSDAY",
              "close_time": { "hours": 22, "minutes": 0 }
            },
            {
              "open_day": "FRIDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "FRIDAY",
              "close_time": { "hours": 23, "minutes": 0 }
            },
            {
              "open_day": "SATURDAY",
              "open_time": { "hours": 10, "minutes": 0 },
              "close_day": "SATURDAY",
              "close_time": { "hours": 23, "minutes": 0 }
            },
            {
              "open_day": "SUNDAY",
              "open_time": { "hours": 10, "minutes": 0 },
              "close_day": "SUNDAY",
              "close_time": { "hours": 20, "minutes": 0 }
            }
          ]
        },
        "brand_landing_pages": [
          {
            "brand_id": "tasty_bites_brand",
            "localized_landing_pages": [
              {
                "url": "https://www.tastybitestest.com/en",
                "locales": ["en-US", "en-GB"]
              }
            ],
            "default_url": "https://www.tastybitestest.com"
          }
        ]
      }
    }
  ]
}

Multi-lingual POI Feed

Filename: poi_multilingual.json

{
  "data": [
    {
      "poi_id": "test_restaurant_1",
      "name": {
        "localizations": [
          {
            "locale": "en",
            "text": "Tasty Bites Test Restaurant"
          },
          {
            "locale": "fr",
            "text": "Restaurant de test Tasty Bites"
          }
        ],
        "default_locale": "en"
      },
      "telephone": "+1234567890",
      "url": "https://www.tastybitestest.com",
      "location": {
        "latitude": 37.422,
        "longitude": -122.084,
        "address": {
          "country": "US",
          "locality": "Mountain View",
          "postal_code": "94043",
          "street_address": "1600 Amphitheatre Pkwy"
        }
      },
      "display_address": {
        "localizations": [
          {
            "locale": "en",
            "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
          },
          {
            "locale": "fr",
            "text": "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
          }
        ],
        "default_locale": "en"
      },
      "images": [
        {
          "url": "https://www.tastybitestest.com/images/interior.jpg",
          "alt_text": {
            "localizations": [
              {
                "locale": "en",
                "text": "Cozy dining area of Tasty Bites"
              },
              {
                "locale": "fr",
                "text": "Espace salle à manger accueillant de Tasty Bites"
              }
            ],
            "default_locale": "en"
          }
        }
      ],
      "rating": 4.7,
      "num_ratings": 150,
      "rating_scale": 5,
      "category": "LOCAL",
      "description": {
        "localizations": [
          {
            "locale": "en",
            "text": "A mock restaurant for testing the POI feed ingestion."
          },
          {
            "locale": "fr",
            "text": "Un faux restaurant pour tester l'ingestion de flux de points d'intérêt."
          }
        ],
        "default_locale": "en"
      },
      "local_data": {
        "establishment_category": {
           "localizations": [
             {
               "locale": "en",
               "text": "Restaurant"
             },
             {
               "locale": "fr",
               "text": "Restaurant"
             }
           ],
           "default_locale": "en"
        },
        "price_range": {
          "min_price": {
            "currency_code": "USD",
            "units": 15,
            "nanos": 0
          },
          "max_price": {
            "currency_code": "USD",
            "units": 45,
            "nanos": 0
          }
        },
        "business_hours": {
          "time_ranges": [
            {
              "open_day": "MONDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "MONDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "TUESDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "TUESDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "WEDNESDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "WEDNESDAY",
              "close_time": { "hours": 21, "minutes": 0 }
            },
            {
              "open_day": "THURSDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "THURSDAY",
              "close_time": { "hours": 22, "minutes": 0 }
            },
            {
              "open_day": "FRIDAY",
              "open_time": { "hours": 11, "minutes": 0 },
              "close_day": "FRIDAY",
              "close_time": { "hours": 23, "minutes": 0 }
            },
            {
              "open_day": "SATURDAY",
              "open_time": { "hours": 10, "minutes": 0 },
              "close_day": "SATURDAY",
              "close_time": { "hours": 23, "minutes": 0 }
            },
            {
              "open_day": "SUNDAY",
              "open_time": { "hours": 10, "minutes": 0 },
              "close_day": "SUNDAY",
              "close_time": { "hours": 20, "minutes": 0 }
            }
          ]
        },
        "brand_landing_pages": [
          {
            "brand_id": "tasty_bites_brand",
            "localized_landing_pages": [
              {
                "url": "https://www.tastybitestest.com/fr",
                "locales": ["fr-FR", "fr-CA"]
              },
              {
                "url": "https://www.tastybitestest.com/en",
                "locales": ["en-US", "en-GB"]
              }
            ],
            "default_url": "https://www.tastybitestest.com"
          }
        ]
      }
    }
  ]
}