Restaurant Recommendations


Public Beta Feature

This documentation covers a feature currently in Public Beta. Access is available to anyone interested in building personalized experiences for their end-users.

This feature is subject to the Personalization API (Self-Service) Public Beta End user License Agreement 📄.

Curate a Unique Gastro Journey

Use our Movement SDK to reach users with the right messaging at the right place and time, whether they want quick takeout/delivery or “foodies” who are searching for a planned in-advance dinner.

Jump-start personalization during user app onboarding by integrating our Tastes endpoints with your customer data platform to maintain a detailed user persona profile based on user interests and preferences.

Using our Search endpoints, enhance customer trust by showing venue recommendations tailored to their unique interests and preferences.

Features Used

Our restaurant recommendation mobile app use case leverages the following features to achieve the afore-mentioned user experience.

Movement SDK

  • Snap to Place Technology to generate visit events and feed the recommendations algorithm
  • Geofences for event detection on a specified set of lat/longs, POIs, categories, or chains.

Personalization API Endpoints

  • Tastes to identify a user’s preferences - cuisine, specific dishes or drinks, ambience, suitability for specific occasions - to jump start personalization.
  • Search to inspire your users to discover new places around them.

Get Started

Step 1. Set up Your FSQ Developer Account

Step 2. Install and Configure the Movement SDK

Step 3. Build the API Calls

Step 4. Integrate API Calls Into Your App Code

The following code written in Swift for an iOS app provides an example of how to call Foursquare’s Tastes endpoints to understand their preferences and make venue recommendations based on those preferences..

Please make sure to include the unique per app user oauth_token to ensure a personalized experience. Learn more about Foursquare’s User-ful Authentication.

import Foundation

let v = "20231020"
let oauthToken = "[TOKEN]"

struct FoursquareResponse<ResponseType: Codable>: Codable {
    struct Meta: Codable {
        let code: Int
        let requestId: String

    let meta: Meta
    let response: ResponseType

struct EmptyResponse: Codable {


struct HTTPError: Error {
    let statusCode: Int

    static let badRequest = HTTPError(statusCode: 400)
    // ... more statuses

func makeRequest(endpoint: String, method: String, params: [String: String]) async throws -> Data {
    let components = {
        var components = URLComponents(string: "\(endpoint)")!
        components.queryItems = [
            URLQueryItem(name: "v", value: v),
            URLQueryItem(name: "oauth_token", value: oauthToken)
        ] + { URLQueryItem(name: $0.key, value: $0.value) }
        return components

    let request = {
        var request = URLRequest(url: components.url!)
        request.httpMethod = method
        return request

    let result = try await request)
    guard let response = result.1 as? HTTPURLResponse, response.statusCode < 400 else {
        throw HTTPError(statusCode: (result.1 as? HTTPURLResponse)?.statusCode ?? HTTPError.badRequest.statusCode)
    return result.0

struct Venue: Codable {
    let id: String
    let name: String

struct User: Codable {
    let id: String
    let firstName: String
    let lastName: String
//    ...

struct Taste: Codable {
    let id: String
    let text: String

struct GetTasteSuggestionsResponse: Codable {
    let tastes: [Taste]

struct GetVenueRecommendationsResponse: Codable {
    struct Group: Codable {
        struct Result: Codable {
            let venue: Venue
        let results: [Result]
    let group: Group

func getTasteSuggestions(intent: String) async throws -> [Taste] {
    let data = try await makeRequest(endpoint: "/tastes/suggestions", method: "GET", params: ["intent": intent])
    return try JSONDecoder().decode(FoursquareResponse<GetTasteSuggestionsResponse>.self, from: data).response.tastes

func addTaste(taste: Taste) async throws {
    try await makeRequest(endpoint: "/tastes/add", method: "POST", params: ["tasteId":])

func getVenueRecommendations(latLng: String) async throws -> GetVenueRecommendationsResponse {
    let data = try await makeRequest(endpoint: "/search/recommendations", method: "GET", params: ["ll": latLng])
    return try JSONDecoder().decode(FoursquareResponse<GetVenueRecommendationsResponse>.self, from: data).response

let tastes = try await getTasteSuggestions(intent: "tipstream")
if let taste = tastes.first {
    try await addTaste(taste: taste)
let latLng = "40.7591622,-74.0516322"
print(try await getVenueRecommendations(latLng: latLng))