Engine Mobile SDK

Following is documentation and examples for running Engine in your app. Note that the current release (2.12.1) does not support remote configuration of circumstances. In this release, circumstance may only be defined programmatically, then compiled into your app.


Circumstances are the primary element of Engine.

Following are some typical circumstances you might configure Engine to handle:

  • Any time a user is at a restaurant on a weekend night, in an area they don’t often frequent, and they are near a bar that will be showing live music in an hour.
  • Any time a user is at a coffee shop they’ve never been to, but the user regularly frequents other coffee shops.
  • Any time a user is at a big electronics store that is closed, and is near another one that is open.

Defining Circumstances

Circumstances are defined as S-expressions. We’ve chosen this format because it’s:

  • Efficient.
  • Flexible.
  • Familiar to most programmers.
  • Platform neutral.
  • Generally easy to read.


  • Currently, the syntax consists of the these predicates: (and ...), (or ...), (not ...), (at ...), (near ...), (= ...), (any-of ...), is-open, any-factual-place and true. More will be added later.
  • and, or, and not can be nested in one another.
  • at/near can’t contain at/near expressions.
  • =/any-of, is-open and any-factual-place can only appear within at/near expressions.
  • Sub-expressions of at/near expressions are implicitly anded together.
  • A near expression must have at least one sub-expression. The first sub-expression is the pre-filter, which must be either an =/any-of expression or an or of =/any-of expressions.
  • An =/any-of predicate must be in the form (= factual-id "foo"), where the second element of the list is one of factual-id, category-id, chain-id or threshold-met.
  • The any-of predicate must be in the form (any-of factual-id "foo" "bar"), like = but variadic.
  • An =/any-of expression whose second element is threshold-met must have values "high", "low" or "near".

The DSL runner returns only a boolean result initially. Another method returns the relevant at and near places.

Places for an at/near expression are returned if the at/near is the only filter or is only in an or. If the at/near is in an and, the places are only returned if the outermost and succeeds. An at/near inside a not never returns the places.

Currently is-open for a place that doesn’t have an hours field is false.


The following examples reference Factual Ids, category Ids, and chain Ids.

At any place (in Factual’s Places Data)

(at any-factual-place)

At any restaurant

(at (= category-id 347))
  • 347 is the category Id for Social > Food and Dining > Restaurants

At any restaurant or a bar

(or (at (= category-id 312)) (at (= category-id 347)))
  • 312 is the category Id for Social > Bars
  • 347 is the category Id for Social > Food and Dining > Restaurants

At any restaurant or a bar, using the any-of shorthand

(at (any-of category-id 312 347))

At a Starbucks near a Peet’s Coffee & Tea

(and (at (= chain-id "ab4c54c0-d68a-012e-5619-003048cad9da"))
     (near (= chain-id "e60a5d2d-6e9e-4d3b-bfe4-5cebfc0c3d97")))
  • “ab4c54c0-d68a-012e-5619-003048cad9da” is the chain Id for Starbucks.
  • “e60a5d2d-6e9e-4d3b-bfe4-5cebfc0c3d97” is the chain Id for Peet’s Coffee & Tea.

At a closed Best Buy, near any open electronics store

(and (at (= chain-id "ab4affd0-d68a-012e-5619-003048cad9da") (not is-open))
     (near (= category-id 133) is-open))
  • “ab4affd0-d68a-012e-5619-003048cad9da” is the chain Id for Best Buy
  • 133 is the category Id for Retail > Computers and Electronics

Near the Los Angeles Staples Center

(near (= factual-id "d9d3c9e1-983d-438b-8970-ebaddaa71386"))
  • “d9d3c9e1-983d-438b-8970-ebaddaa71386” is the Factual Id for the Staples Center.

Increased At Confidence Threshold

The default threshold for Engine determining a user is at a place is "low". It is intended to provide a reasonable level of confidence that the device is at the place defined in your DSL expression. If you find that the false positive rate for users being at specific places is too high for your use case, you can override the threshold:

(at (= chain-id "ab4c54c0-d68a-012e-5619-003048cad9da")
    (= threshold-met "high"))

Register a Circumstance Notifier

Engine will monitor for the device fulfilling the specified circumstance when the device has either arrived at or departed from a location, and will notify your delegate if the circumstance has been met.

[[FactualEngine sharedEngine]
                                expr:@"(at (= chain-id \"ab4c54c0-d68a-012e-5619-003048cad9da\"))"
parameter description
registerCircumstanceNotifierWithId Provide a unique identifier for this circumstance. You may need this to stop/restart the circumstance. Also, if you have multiple circumstances mapped to the same delegate, you can use this Id to determine which circumstance generated the callback to your delegate.
expr An expression representing the circumstance you are detecting. Expressions are documented above.
when When this circumstance is evaluated (either @"arriving", @"departing").
delegate A delegate implementing the FactualCircumstanceDelegate interface.

Disable Circumstance Notifier

Temporarily cease monitoring of a specified circumstance:

[[FactualEngine sharedEngine] disableCircumstanceNotifierWithId:@"my_circumstance"];
parameter description
disableCircumstanceNotifierWithId A unique identifier for the circumstance notifier to be disabled.

Re-enable Circumstance Notifier

Re-enable monitoring a specified circumstance:

[[FactualEngine sharedEngine] enableCircumstanceNotifierWithId:@"my_circumstance"];
parameter description
enableCircumstanceNotifierWithId A unique identifier for the circumstance notifier to be enabled.

Unregister a Circumstance

Permanently cease monitoring for a specified circumstance:

[[FactualEngine sharedEngine] unregisterCircumstanceWithId:@"my_circumstance"];
parameter description
unregisterCircumstanceWithId A unique identifier for the circumstance notifier to be removed.

Handling Circumstances

In order to handle notification of a circumstance being met, you will need to define a delegate implementing the FactualCircumstanceDelegate interface:

// the circumstance was met.
- (void)factualCircumstanceDidOccur:(FactualCircumstance *)circumstance;

// something went wrong
- (void)factualCircumstance:(FactualCircumstance *)circumstance didFailWithError:(NSError *)error;

// some data was generated for debugging purposes.
- (void)factualCircumstance:(FactualCircumstance *)circumstance didReportDebugInfo:(id)debugInfo;

Current Location

Engine enables you to use its on-device places data to generate a list of potential “check-in” candidates at the current location of the device.

Getting the Place Candidates

You get a list of candidates as follows:

// get a list of place candidates:
[[FactualEngine sharedEngine] genPlaceCandidatesWithDelegate: self];
parameter description
genPlaceCandidatesWithDelegate A delegate implementing the FactualDataRequestDelegate interface.

Handling Place Candidates

In order to handle a place candidate list being returned, you will need to define a delegate implementing the FactualCircumstanceDelegate interface:

// the results were returned
- (void)factualDataRequest:(FactualDataRequest *)request didFinishWithData:(id)data;

// an error occurred generating the results.
- (void)factualDataRequest:(FactualDataRequest *)request didFailWithError:(NSError *)error;

The FactualDataRequestDelegate accepts the candidates as an NSDictionary object containing:

  • An array of activities (currently, only “walking” or “driving”).
  • An array of places
  • The latitude and longitude of the device
  • A set of sensor_windows (used for debugging only)

For each place, you’ll receive:

  • name of the place
  • place_id
  • an array of Factual category ids
  • chain id (optional)
  • latitude/longitude of the place
  • distance, in meters, from the device to the place
  • threshold_met (either “high”, “low”, or “near”)

Place Verification

Verifying locations after users have manually indicated their location (e.g., picked a location from a candidate list) can help improve future accuracy of the current location candidates for your app.

If, after presenting the list of place candidates to your end user, the user verifies the location by means of some kind of check-in UI or similar, you can log the verified location as follows:

[[FactualEngine sharedEngine] verifyLocation:@"b8804733-db42-4ac0-8816-fbe2cdd78c96"];
parameter description
verifyLocation Factual Id of the verified location. Note that the Factual ID MUST be present in the result set from the preceding genPlaceCandidatesWithDelegate invocation.