Add Features

The Movement SDK also offers features which you can use to augment your in-app experience, bringing location to the forefront to offer more compelling interactions to your users.

Journeys

Journeys allows partners to build powerful, location-aware experiences. You can use Journeys to power in-store & curbside pickup, delivery tracking, location-based marketing, and more.

When a user is ready to embark on a journey (i.e. they tap on "I'm on my way"), Journeys will start monitoring for their arrival, provide live ETAs throughout the way, and automatically detect when a user has arrived at their destination.

Requirements

  • Movement SDK v4.0.0+
  • Background Location & Precise Location Enabled

Required AppDelegate Method

Include the following delegate methods to track journey state/eta/etc. Foursquare will return one of the following journey states:

  • In Progress: The journey has started successfully and will now send regular updates.
  • Approaching: The user is now approaching the destination.
  • Arrived: The user has arrived at the destination.
  • Completed: The journey has been completed. This is a user-generated action
  • Canceled: The journey has been canceled. This is a user-generated action.
protocol MovementSdkManagerDelegate {
…
    fun movementSdkManager(_ movementSdkManager: MovementSdkManager, handleJourneyUpdate journey: Journey)
…
}

Available Methods

Include the following methods to ensure the correct Journeys behaviors are tracked.

// method
MovementSdkManager.sharedManager.start(destinationId: String, destinationType: JourneyDestinationType)
// usage
MovementSdkManager.sharedManager.startJourney(destinationId: venueId, destinationType: .venue, metadata: nil) { error in
    guard error == nil else {
        // handle error
        return
    }
}
// method
func MovementSdkManager.currentJourney() -> Journey?
// usage
if let journey = MovementSdkManager.sharedManager.currentJourney() {
    // do something with journey
}
// method
func MovementSdkManager.cancelJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.cancelJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}
// method
func MovementSdkManager.checkinJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.checkinJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}
// method
func MovementSdkManager.completeJourney(completion: ((Error?) -> Void)? = nil)
// usage
MovementSdkManager.sharedManager.completeJourney { error in
    guard error == nil else {
        // handle error
        return
    }
}

Error Handling

Using the delegate method:

protocol MovementSdkManagerDelegate {
…
    fun movementSdkManager(_ movementManager: MovementSdkManager, handleError error: Error)
…
}

extension FoursquareMovementService: MovementSdkManagerDelegate {
…
    func movementSdkManager(_ movementManager: MovementSdkManager, handleErrror error: Error){
        // handle error
    }
}

Get Current Location

Current Location is the most comprehensive of the in-app features, allowing you to get precise place information for any user who has given your app permission to use location.

For e.g you may want to display a nearby venue to your user, or you may want to determine whether or not to send an in-app notification or display a modal if your user is at or near a specific geofence.

Note: This does not require always on background location and can also handle location scenarios while your users are in motion.

Using Current Location you can:

Get Current Place

Get the same place name, category, and chain information you would receive in the background callbacks in real time in your app.

MovementSdkManager.shared().getCurrentLocation { (currentLocation, error) in
   currentLocation.currentPlace
}

Get Matched Geofences

If you utilize the explicit geofence functionality of the SDK, Current Location will return any Geofence Events, e.g if your user is currently inside one (or many) of your drawn geofences.

MovementSdkManager.shared().getCurrentLocation { (currentLocation, error) in
   currentLocation.matchedGeofences
}

Get Last Known User State

The general location context information delivered through the SDK’s User States features return city, state, zip and country level information - including lat/long coordinates - for all users, in addition to home, work, traveling, commuting for users who have enabled always on location. Please see Access User States for more information.

You can access User State in one of two ways:

func movementSdkManager(_ movementSdkManager: MovementSdkManager, handleUserState updatedUserState: UserState, changedComponents: UserStateComponent) {
    switch changedComponents {
    case .city:
      print("Welcome to \(updatedUserState.city)")
      // handle other cases
    }
  }
  • Accessing via the MovementSdkManager Instance
MovementSdkManager.shared().lastKnownUserState()

Receive Geofence Events

The Movement SDK allows geofencing around a configurable set of venues or points. Geofences can be set for the venues, categories, or chains of your choosing. By default, Foursquare will use its knowledge of the venue's location to return the right fence for a given place. You may also configure a radius of your choosing, but we recommend letting the SDK pick the right one to give you the optimal experience.

Support for polygon shapes and arbitrary latitude/longitude points are also available. This allows greater customization and removes the reliance upon geofencing only Foursquare venue locations.

Why Use Geofences

For use cases that rely on accuracy, regular SDK place visit detection is superior to geofencing. However, there are certain instances where geofencing is preferable:

  • When speed and proximity to a specific subset of venues is more important than accurately detecting visits there.
  • When it’s more important to know if a user is nearby a certain place rather than visiting.
  • When you want to track when users that are en-route to a specific venue, and you want to know as soon as they arrive.

Geofencing runs independently alongside regular SDK visit detection so you can still get the benefit of understanding everywhere your users go while enabling additional use cases.

Event Types

Geofences have five potential event types that are delivered directly to the client and through an optional webhook:

Event TypeDescription
entranceTriggered on the first GPS signal that is received inside of the geofence.
dwellTriggered after the user has "dwelled" within the geofence for a configurable length of time. Default is 1 minute.
venue confirmedTriggered when the device has dwelled inside a geofence radius and confirmed a stop at the venue within the radius. Only available in SDK versions 2.1.2 or greater
exitTriggered on the first GPS signal that is received outside of the geofence.
presenceTriggered when the device is in a geofence radius during a get location request. Only available in SDK versions 2.1 or greater

Receiving Events

To receive geofence events on the client, add the event handler below:

// In your implementation of the Movement SDK delegate, add:
func movementSdkManager(_ movementSdkManager: MovementSdkManager, handle geofenceEvents: [GeofenceEvent]) {
    // Code to handle geofenceEvents...
}

Geofences will need to be set to a specific Foursquare venue, chain, category or shape (see below). For example, a partner could set up geofences for Foursquare HQ, all coffee shops, and all Chick-fil-a’s. You can also set up a geofence for an arbitrary lat/lng or custom polygon shapes. For Foursquare venues, this means that some venue harmonization may need to take place beforehand if you already have a specific list of places you want to geofence.

Note: Geofences are set up globally across all users of the app. User specific geofences are not yet something we provide.

A geofence event will contain the following:

FieldDescription
eventTypeentrance, dwell, venueConfirmed, exit, or presence.
venueSame as regular SDK venue object.
categoryIDsArray of categoryIDs used by triggered geofence.
chainIDsArray of chainIDs used by triggered geofence.
partnerVenueIDString of harmonized venueId.
locationObject containing location information about the geofence event.
timestampUnix/epoch timestamp in milliseconds of when the event occurred.

Webhook Examples

{
  "eventType": "geofenceEnter",
  "timestamp": 1545078269223,
  "geofenceEvent": {
    "eventType": "entrance",
    "eventLat": 41.8893897,
    "eventLng": -87.6297896,
    "radius": 100.0,
    "geofenceId": "5c649335af2c3c526c06a898",
    "geofenceProperties": {
      "customGeofenceKey": "Custom Geofence Value"
    },
    "venueId": "4a9037fef964a5209b1620e3",
    "categoryIds": "4bf58dd8d48988d1e0931735",
    "chainIds": "",
    "partnerVenueId": "",
    "venues": [
      {
        "id": "4a9037fef964a5209b1620e3",
        "name": "Einstein Bros Bagels",
        "location": {
          "address": "400 N Dearborn St",
          "crossStreet": "",
          "city": "Chicago",
          "state": "IL",
          "postalCode": "60654",
          "country": "US",
          "lat": 41.8893897,
          "lng": -87.6297896
        },
        "categories": [
          {
            "id": "4bf58dd8d48988d179941735",
            "name": "Bagel Shop",
            "pluralName": "Bagel Shops",
            "shortName": "Bagels",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/bagels_",
              "suffix": ".png"
            }
          },
          {
            "id": "4bf58dd8d48988d1e0931735",
            "name": "Coffee Shop",
            "pluralName": "Coffee Shops",
            "shortName": "Coffee Shop",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_",
              "suffix": ".png"
            }
          }
        ],
        "venueChains": [
          {
            "id": "556ce8d9aceaff43eb0588d6",
            "name": "Einstein Bros."
          }
        ]
      }
    ]
  },
  "lat": 41.88928251303856,
  "lng": -87.62870316744883,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk",
  "sdkBuild": "2.4.2"
}
{
  "eventType": "geofenceDwell",
  "timestamp": 1545078408140,
  "geofenceEvent": {
    "eventType": "dwell",
    "eventLat": 41.8893897,
    "eventLng": -87.6297896,
    "radius": 100.0,
    "geofenceId": "5c649335af2c3c526c06a898",
    "geofenceProperties": {
      "customGeofenceKey": "Custom Geofence Value"
    },
    "venueId": "4a9037fef964a5209b1620e3",
    "categoryIds": "4bf58dd8d48988d1e0931735",
    "chainIds": "",
    "partnerVenueId": "",
    "venues": [
      {
        "id": "4a9037fef964a5209b1620e3",
        "name": "Einstein Bros Bagels",
        "location": {
          "address": "400 N Dearborn St",
          "crossStreet": "",
          "city": "Chicago",
          "state": "IL",
          "postalCode": "60654",
          "country": "US",
          "lat": 41.8893897,
          "lng": -87.6297896
        },
        "categories": [
          {
            "id": "4bf58dd8d48988d179941735",
            "name": "Bagel Shop",
            "pluralName": "Bagel Shops",
            "shortName": "Bagels",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/bagels_",
              "suffix": ".png"
            }
          },
          {
            "id": "4bf58dd8d48988d1e0931735",
            "name": "Coffee Shop",
            "pluralName": "Coffee Shops",
            "shortName": "Coffee Shop",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_",
              "suffix": ".png"
            }
          }
        ],
        "venueChains": [
          {
            "id": "556ce8d9aceaff43eb0588d6",
            "name": "Einstein Bros."
          }
        ]
      }
    ]
  },
  "lat": 41.889335266663636,
  "lng": -87.62856037188838,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk",
  "sdkBuild": "2.4.2"
}
{
  "eventType": "geofenceVenueConfirmed",
  "timestamp": 1545078428140,
  "geofenceEvent": {
    "eventType": "venueConfirmed",
    "eventLat": 41.8893897,
    "eventLng": -87.6297896,
    "radius": 100.0,
    "venueId": "4a9037fef964a5209b1620e3",
    "categoryIds": "4bf58dd8d48988d1e0931735",
    "chainIds": "",
    "venues": [
      {
        "id": "4a9037fef964a5209b1620e3",
        "name": "Einstein Bros Bagels",
        "location": {
          "address": "400 N Dearborn St",
          "crossStreet": "",
          "city": "Chicago",
          "state": "IL",
          "postalCode": "60654",
          "country": "US",
          "lat": 41.8893897,
          "lng": -87.6297896
        },
        "categories": [
          {
            "id": "4bf58dd8d48988d179941735",
            "name": "Bagel Shop",
            "pluralName": "Bagel Shops",
            "shortName": "Bagels",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/bagels_",
              "suffix": ".png"
            }
          },
          {
            "id": "4bf58dd8d48988d1e0931735",
            "name": "Coffee Shop",
            "pluralName": "Coffee Shops",
            "shortName": "Coffee Shop",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_",
              "suffix": ".png"
            }
          }
        ],
        "venueChains": [
          {
            "id": "556ce8d9aceaff43eb0588d6",
            "name": "Einstein Bros."
          }
        ]
      }
    ]
  },
  "lat": 41.889335266663636,
  "lng": -87.62856037188838,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk"
}
{
  "eventType": "geofenceExit",
  "timestamp": 1545091987992,
  "geofenceEvent": {
    "eventType": "exit",
    "eventLat": 41.8893897,
    "eventLng": -87.6297896,
    "radius": 100.0,
    "geofenceId": "5c649335af2c3c526c06a898",
    "geofenceProperties": {
      "customGeofenceKey": "Custom Geofence Value"
    },
    "venueId": "4a9037fef964a5209b1620e3",
    "categoryIds": "4bf58dd8d48988d1e0931735",
    "chainIds": "",
    "partnerVenueId": "",
    "venues": [
      {
        "id": "4a9037fef964a5209b1620e3",
        "name": "Einstein Bros Bagels",
        "location": {
          "address": "400 N Dearborn St",
          "crossStreet": "",
          "city": "Chicago",
          "state": "IL",
          "postalCode": "60654",
          "country": "US",
          "lat": 41.8893897,
          "lng": -87.6297896
        },
        "categories": [
          {
            "id": "4bf58dd8d48988d179941735",
            "name": "Bagel Shop",
            "pluralName": "Bagel Shops",
            "shortName": "Bagels",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/bagels_",
              "suffix": ".png"
            }
          },
          {
            "id": "4bf58dd8d48988d1e0931735",
            "name": "Coffee Shop",
            "pluralName": "Coffee Shops",
            "shortName": "Coffee Shop",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_",
              "suffix": ".png"
            }
          }
        ],
        "venueChains": [
          {
            "id": "556ce8d9aceaff43eb0588d6",
            "name": "Einstein Bros."
          }
        ]
      }
    ]
  },
  "lat": 41.88709567122635,
  "lng": -87.63105850113463,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk",
  "sdkBuild": "2.4.2"
}
{
  "eventType": "geofencePresence",
  "timestamp": 1549553712000,
  "geofenceEvent": {
    "eventType": "presence",
    "eventLat": 41.8893897,
    "eventLng": -87.6297896,
    "radius": 100.0,
    "geofenceId": "5c649335af2c3c526c06a898",
    "geofenceProperties": {
      "customGeofenceKey": "Custom Geofence Value"
    },
    "venueId": "4a9037fef964a5209b1620e3",
    "categoryIds": "4bf58dd8d48988d1e0931735",
    "chainIds": "",
    "partnerVenueId": "",
    "venues": [
      {
        "id": "4a9037fef964a5209b1620e3",
        "name": "Einstein Bros Bagels",
        "location": {
          "address": "400 N Dearborn St",
          "crossStreet": "",
          "city": "Chicago",
          "state": "IL",
          "postalCode": "60654",
          "country": "US",
          "lat": 41.8893897,
          "lng": -87.6297896
        },
        "categories": [
          {
            "id": "4bf58dd8d48988d179941735",
            "name": "Bagel Shop",
            "pluralName": "Bagel Shops",
            "shortName": "Bagels",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/bagels_",
              "suffix": ".png"
            },
            "primary": true
          },
          {
            "id": "4bf58dd8d48988d1e0931735",
            "name": "Coffee Shop",
            "pluralName": "Coffee Shops",
            "shortName": "Coffee Shop",
            "icon": {
              "prefix": "https://ss3.4sqi.net/img/categories_v2/food/coffeeshop_",
              "suffix": ".png"
            }
          }
        ],
        "venueChains": [
          {
            "id": "556ce8d9aceaff43eb0588d6",
            "name": "Einstein Bros."
          }
        ]
      }
    ]
  },
  "lat": 41.889356,
  "lng": -87.628725,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk",
  "sdkBuild": "2.4.2"
}

Geofence Management

Geofences can be managed through the Geofence builder in your Developer Console or via our Geofence API.

Set Custom User Data

With the updates regarding privacy in the release of iOS 14, app users will now have the option not to share their IDFA. For more information, see our blog post on iOS14 and our iOS14+ section.

The SDK enables developers to set custom user unique identifiers in addition to or as a replacement for the IDFA. This is common if you want to tie an SDK event to a specific user in your own database or in a third-party integration.

For example, if your app is using a mobile number and/or an email as a user unique identifier, you can decide to add one or both to your SDK events. Once set, the custom user data will be passed along in the SDK webhook payload.

Where to set custom user data

Generally, we recommend that you set custom user info or user unique identifiers, as soon as you have a way to identify your user i.e upon logging in or once you have their session in the app.

While you do not need to worry about modifying the Movement SDK when a user revokes location permissions, if a user logs out of your app, you should call MovementSdk.clearAllData() to reset any unique identifiers that you may have configured.

Examples

let userInfo = UserInfo()

// the String myCustomUserId would be a previously set variable that stores the user's unique id:
userInfo.setUserId(myCustomUserId)

// You can also set other custom fields using the setUserInfo method, where both function parameters accept strings:
userInfo.setUserInfo("+123456789", forKey: "phoneNumber")
userInfo.setUserInfo("[email protected]", forKey: "emailAddress")

// Starting in v2.1.2, you have the ability to persist user info across sessions:
MovementSdkManager.shared().setUserInfo(userInfo, persisted: true)

// To unset persisted fields:
MovementSdkManager.shared().setUserInfo(nil, persisted: true)

Testing

There are two ways to test and confirm that you're successfully setting custom user data, via:

Access User States

User states allow you to more accurately interact, or not interact, with your users based on their state. For example, you might not want to send a notification to any users that are at home but you may want to remind them of a great promotion while they are on their way to work or on vacation.

Home and Work

As users of your app begin to establish regular behavior (usually after 3-7 week days), the SDK will attempt to determine their home and work locations. This is a foundational feature of the SDK that is often used in the calculation of other user states.

Note: The home and work locations that the SDK determines are a generalized "area", not a specific address. Instead of a specific venue, the arrival/departure events will designate the locationType as home or work instead of venue. For example, a webhook payload for a work arrival might look something like this:

{
  "movementSdkVisitId": "4c4b64fdd807ee002cba1560",
  "eventType": "placeArrival",
  "timestamp": 1548444925000,
  "placeEvent": {
    "venues": [],
    "confidence": "high",
    "locationType": "work",
    "arrivalTime": 1548444925000
  },
  "lat": 41.889282,
  "lng": -87.62858,
  "user": {
    "adid": "40C23EBD-E21A-4ACC-A915-B1C80BDAF4FE",
    "userId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4"
  },
  "installId": "CB25EFFB-C2B2-4E0F-B0E9-55C05BEFA4D4",
  "sdkType": "iossdk",
  "sdkBuild": "2.4.2",
  "segments": [
    {
      "segmentId": 162,
      "name": "The Foursquare Coffee Drinker - U.S."
    }
  ]
}

To check if a user has configured their home/work locations, you can see if this has been set by checking the hasHomeOrWork property:

MovementSdkManager.shared().hasHomeOrWork()

Note: It's possible that you won't want to process any visits or only trust visits that have a 'High' confidence until home/work has been set. This is due to the fact that a user's home is not in our venue database, so we may be attributing 'home' visits to a venue nearby until we learn that this is in fact their home.

See an example of this simple check on iOS is below.

func movementSdkmManager(_ movementSdkManager: MovementSdkManager, didVisit visit: Visit) {
    if movementSdkManager.hasHomeOrWork() {

        // Home and work are set. Lets print them out
        print(movementSdkManager.homeLocations)
        print(movementSdkManager.workLocations)

    } else if visit.confidence != .high {
        // Home and work aren't set and visit confidence isn't High
        // Depending on my application I might not want to trust this visit
    }

}

Additional States

Non Home and Work user states are accessible via the lastKnownUserState property on the MovementSdkManager instance. This object will have a coordinate, timestamp and a state property.

Note: It is always a good idea to check the timestamp and coordinate of this property, as it’s possible that the user may have moved since the last time the user state was updated.


If you'd like to be notified of any changes in user state, you can do so via the handleUserState callback.

Travel

We calculate the travel state by observing users home/work visit patterns. States trigger when users deviate from those patterns in a way that signifies traveling. This can be useful if you want to send targeted messaging that relates to a user traveling, as opposed to being in their normal home/work routine.

Commute

The Movement SDK defines commuting as when a user is moving some distance between one's home and place of work on a regular basis. This can be useful, for example, if you want to send targeted messaging that relates to their morning or evening commute: "Need a pick me up? Stop by and grab a cup of joe on your way into the office."

Location Context

As part of enhancing and extending User State, the SDK also provides an additional Location Context.This can be useful for providing a contextual notification based on a regional change in your user's location. For example, your user entering the City of Wheaton.

The Location Context includes the following:

  • State
  • City
  • Postal Code
  • Country
  • DMA

Examples

MovementSdkManager.shared().lastKnownUserState()

For examples of how user states are sent via webhook events, see the webhook examples.

Provide Visit Feedback

One of the best ways to help us improve the accuracy of the Movement SDK and where we think devices are located is by providing feedback about a user's visit. The more feedback we get, the smarter, faster and more accurate visits from the Movement SDK become. We provide the following methods to provide feedback.

Confirm and Deny a Visit

You can easily confirm whether a visit is accurate or not (and why). All you need is the movementSdkVisitId from the original visit.

/**
 *  @param visitId          The visit ID to provide feedback for.
 *  @param feedback         See FSQVisitFeedback below for options.
 *  @param actualVenueId    If the correct Foursquare venue ID is known, let the SDK know.
 *  @param completion       A completion handler called when the transaction finishes.
 */

MovementSdkManager.shared().feedbackProvider.leaveVisitFeedback(feedback: FeedbackProvider.VisitFeedback, visitId: String, actualVenueId: String?, completion: ((Error?) -> Void)

The available feedback options are:

Feedback Description
VisitFeedback.confirm The visit was at the correct venue.
VisitFeedback.falseStop The user did not stop anywhere. If you are unsure, use deny
VisitFeedback.wrongVenue The wrong venue was detected. A Foursquare venue id can optionally be included to identify the correct venue.
VisitFeedback.deny Generic feedback that something was incorrect. If your feedback interface doesn’t allow for wrongVenue or falseStop or you are unsure, use this.

An example providing wrongVenue feedback with the correct venueId:

MovementSdkManager.shared().feedbackProvider?.leaveVisitFeedback(feedback: .wrongVenue,
                                                             visitId: visit.movementSdkVisitId,
                                                             actualVenueId: "4ed92126f5b92139871ce962",
                                                             completion: nil)

A more robust example of how you might add a feedback drawer to easily allow users to confirm or deny the accuracy of their visit on iOS can be found here.

Check-in at a FSQ Venue

If you know a device is at a specific Foursquare venue, irrespective of receiving an SDK Visit, you can also inform the SDK by providing the Foursquare venue ID:

/**
 *  @param venueId    The foursquare venue ID where you believe the device is currently at.
 */

MovementSdkManager.shared().feedbackProvider?.checkIn(venueId: String)

An example:

let foursquareHQVenueId = "4ef0e7cf7beb5932d5bdeb4e";
MovementSdkManager.shared().feedbackProvider?.checkIn(venueId: foursquareHQVenueId)

Check-in at a Partner Venue

For partners that have already harmonized their venues with Foursquare, irrespective of receiving an SDK Visit, you can also inform the SDK that a device is at a venue by providing the partner's harmonized venue ID:

/**
 *  @param partnerVenueId   A partner venue ID, that is harmonized with Foursquare, where you believe the device is currently at.
 */

MovementSdkManager.shared().feedbackProvider?.checkIn(partnerVenueId: String)

An example:

// (string) where venueId is a previously set variable that consists of an existing harmonized partner's venue ID.
MovementSdkManager.shared().feedbackProvider?.checkIn(partnerVenueId: venueId)