NAV Navbar
javascript objective_c swift java


Welcome to Flomio! Get familiar with the Flomio products and explore their features in the Flomio Shop

Flomio builds hardware and software solutions in the proximity ID space. Flomio makes it easy to integrate our readers into your applications.

As we migrate from native mobile SDKs, please refer to the Javascript SDK for the most up to date documentation.

Getting Started

Flomio helps you build apps with NFC support so you can scan a tag to get a unique ID or read data. If after reading through this you still need help, feel free to ask on the forums.

The Flomio SDK consists of a Javascript SDK that enables reading NFC tags connected via USB without having to deal with the stress of managing the low-level interactions between the reader and tag. The Flomio SDK checks for proper a reader license on our cloud server so it requires connectivity to work.

Javascript Integration

Visit the flomio-js-sdk Github repoistory for instructions to get started using the Javascript SDK within your project.

// Visit for documentation of the Javascript SDK

iOS Integration (Deprecated)

Our iOS libraries let you easily collect your customers/items tag information in your iOS app. Follow the instructions below to add the SDK to your project.

To be sure your reader hardware is fully operational you should install the Flomio Test app via TestFlight. This will help resolve most issues you may encounter during your integration. Our native libraries for Android and iOS and a cross-platform Javascript library are deprecated and not currently supported as we move to focus our efforts on the Javascript SDK.

Install Flomio Test app

You can now register to download the Flomio Test app via TestFlight. Once registered, you’ll receive an email from the Apple TestFlight system directing you to install the TestFlight app and subsequently the Flomio Test app from within TestFlight. Once installed, the Flomio Test app will launch with a menu of our supported readers including:

You will need to plug in the FloJack readers into the audio jack port of your iOS device or power on the FloBLE readers before selecting the appropriate reader from the menu. In order for the FloJack readers to operate well, make sure the volume of your iOS device is raised to the max. This is because the data is exchanged via audio modulation so the higher signal strength, the better data is captured by the reader. Also, the readers should be fully charged for the best results. This is done by plugging in the readers to USB power and observing charging RED led indicator goes off. At this point, the device is fully charged.

Download the Framework

Download the latest Flomio SDK and unzip it.

Build the Example App

Example iOS projects can be seen on the flomio-sdk-ios repo.

Cocoapods and Carthage

To use the FlomioSDK with Cocoapods, follow the instructions from the flomio-sdk-ios repo.

You can also manage your project’s FlomioSDK dependency using Carthage.

Follow these instructions to get setup.

Add github "" to your Cartfile before running carthage update. You will still need to configure your project settings by following the steps in the Configure Project Settings section.

Configure Project Settings

  1. Drag+drop the FlomioSDK.framework file into your Xcode Project. Make sure the “Copy items if needed” option is selected and click “Create groups” and “Finish” in dialog. It will be added to “Linked Frameworks and Libraries” section in project settings.

  2. In Targets -> YourAppTarget -> General -> Embedded Binaries, add the FlomioSDK

  3. You must configure your application with the following settings.
    Click the Project Navigator (on the left), then click the application name under TARGET. In Targets -> YourAppTarget -> Build Settings -> Linking -> Other Linker Flags add ‘-lc++’ and ’-ObjC’

  4. In Targets -> YourAppTarget -> Build Options -> Enable Bitcode set to ‘No’

  5. In Targets -> YourAppTarget -> Build Phases -> Link Binary with Libraries, add MediaPlayer.Framework and libz.tbd

  6. (optional) In Target -> Build Settings -> Apple LLVM 9.0-Preprocessing -> Preprocessor Macros add ‘DEBUGLOG’

Initialize the Flomio SDK

You should only initialize the SDK once per session. This should be called when you want to use your reader, after that you should use the startReaders and stopReaders methods on FmSessionManager to control the readers. See FmConfiguration for more information on the configuration.

    // in YourViewController.h, add this to viewDidLoad
    #import <FlomioSDK/FlomioSDK.h>
    // For Pro Users
    // #import <FlomioSDKPro/FlomioSDKPro.h>

    @interface ViewController : UIViewController <FmSessionManagerDelegate> {  
        NSString *_deviceUid;
        FmSessionManager *flomioSDK;


    // in YourViewController.m, add this to viewDidLoad
    - (void)viewDidLoad {
        FmConfiguration *defaultConfiguration = [[FmConfiguration alloc] init];
        defaultConfiguration.deviceType = kFloBlePlus;
        defaultConfiguration.scanSound = @YES;
        defaultConfiguration.scanPeriod = @1000;
        defaultConfiguration.powerOperation = kAutoPollingControl;
        defaultConfiguration.transmitPower = kHighPower;
        defaultConfiguration.allowMultiConnect = @NO;
        defaultConfiguration.specificDeviceUid = nil;
        flomioSDK = [[FmSessionManager flomioMW] initWithConfiguration:defaultConfiguration];
        flomioSDK.delegate = self;

    import FlomioSDK 
    // For Pro Users
    // import FlomioSDKPro

    class ViewController: UIViewController, FmSessionManagerDelegate {

        var flomioSDK : FmSessionManager = FmSessionManager()
        var deviceUid = ""

        override func viewDidLoad() {

            let defaultConfiguration: FmConfiguration = FmConfiguration();
            defaultConfiguration.deviceType = DeviceType.kFloBlePlus;
            defaultConfiguration.transmitPower = TransmitPower.highPower;
            defaultConfiguration.scanSound = true;
            defaultConfiguration.scanPeriod = 1000;
            defaultConfiguration.powerOperation = PowerOperation.autoPollingControl;
            defaultConfiguration.allowMultiConnect = false;
            flomioSDK = FmSessionManager.init(configuration: defaultConfiguration);
            flomioSDK.delegate = self; 


Listen for Reader Events

See FmSessionManagerDelegate Methods for more information on the delegate methods.

    - (void)didFindTag:(FmTag *)tag fromDevice:(NSString *)deviceUid{


    - (void)didReceiveReaderError:(NSError *)error {


    - (void)didChangeCardStatus:(CardStatus)status fromDevice:(NSString *)deviceUid{


    - (void)didChangeStatus:(NSString *)deviceUid withConfiguration:(FmConfiguration *)configuration andBatteryLevel:(NSNumber *)batteryLevel andCommunicationStatus:(CommunicationStatus)communicationStatus withFirmwareRevision:(NSString *)firmwareRev withHardwareRevision:(NSString *)hardwareRev{

    - (void)didGetLicenseInfo:(NSString *)deviceUid withStatus:(BOOL)isRegistered{


    func didFind(_ tag: FmTag!, fromDevice deviceId: String!) {


    func didChangeStatus(_ deviceUid: String!, with configuration: FmConfiguration!, andBatteryLevel batteryLevel: NSNumber!, andCommunicationStatus communicationStatus: CommunicationStatus, withFirmwareRevision firmwareRev: String!, withHardwareRevision hardwareRev: String!) {


    func didGetLicenseInfo(_ deviceUid: String!, withStatus isRegistered: Bool) {


    func didChange(_ status: CardStatus, fromDevice device: String!) {


    func didReceiveReaderError(_ error: Error!) {


Reading Tags

In the didFindTagFromDevice callback, call the readNdef method on the FmTag object to read NDEF formatted data from your tag. Within the completion handler, iterate through the FmNdefRecords in the FmNdefMessage to see the payload present in your tag. If there is a URL, our SDK provides a convenience parameter with the URL as a string.

    - (void)didFindTag:(FmTag *)tag fromDevice:(NSString *)deviceUid{
        [tag readNdef:^(FmNdefMessage *ndef) {
            if (ndef.ndefRecords) {
                for (FmNdefRecord *record in ndef.ndefRecords) {
                    if (record.url.absoluteString.length > 0){
                        // if there is a URL present in your tag, it will be here

    func didFind(_ tag: FmTag!, fromDevice deviceId: String!) {
        tag.readNdef { (ndefMessage) in
            guard let ndefRecords = ndefMessage?.ndefRecords else { return }
            for case let record as FmNdefRecord in ndefRecords {
               for case let record as FmNdefRecord in ndefRecords {
                   guard let url = record.url else { return }
                   // if there is a URL present in your tag, it will be here

Writing to Tags

Writing a Web Address to Tags

In the didFindTagFromDevice callback, initialize a FmNdefMessage with the createURIWithString method and use it as a parameter on writeNdef method on the FmTag object to begin writing. The completion handler will indicate whether your operation was successful.

      - (void)didFindTag:(FmTag *)tag fromDevice:(NSString *)deviceUid{
          FmNdefMessage *message = [FmNdefMessage createURIWithString:@""];
          [tag writeNdef:message success:^(BOOL success) {
              if (success) {
                NSLog(@"Tag written successfully");

      func didFind(_ tag: FmTag!, fromDevice deviceId: String!) {
          let ndefMessage = FmNdefMessage.createURI(with: "")
          tag.writeNdef(ndefMessage) { (success) in
             if (success) {
               print("Tag written successfully")

Writing Text Data to Tags

In the didFindTagFromDevice callback, create one or more FmNdefRecords and initialize a FmNdefMessage with them. Call the writeNdef method on the FmTag object to begin writing. The completion handler will indicate whether your operation was successful.

     - (void)didFindTag:(FmTag *)tag fromDevice:(NSString *)deviceUid{
         NSData *type = [@"text/plain" dataUsingEncoding:NSASCIIStringEncoding];
         NSData *payload = [@"Hello World!" dataUsingEncoding:NSASCIIStringEncoding];
         FmNdefRecord *record = [[FmNdefRecord alloc] initWithTnf:kTNFMimeMedia andType:type andId:nil andPayload: payload];
         FmNdefMessage *message = [[FmNdefMessage alloc] initWithNdefRecords:@[record]];
         [tag writeNdef:message success:^(BOOL success) {
             if (success) {
               NSLog(@"Tag written successfully");

     func didFind(_ tag: FmTag!, fromDevice deviceId: String!) {
         let type = "text/plain".data(using: .ascii)
         let record = FmNdefRecord.init(tnf: Int16(kTNFMimeMedia), andType: type, andId: nil, andPayload: "Hello World!".data(using: .ascii))
         let message = FmNdefMessage.init(ndefRecords: [record!])
         tag.writeNdef(message) { (success) in
           if (success) {
             print("Tag written successfully")

Find UHF RFID tags

For FloJack Gen 2 device only. Use the rfidTagsToFind parameter on the FmConfiguration object to only target specific tags. You must initialize a new FmConfiguration and call the setConfiguration method on the FmSessionManager object.

      FmConfiguration *config = [[FmConfiguration alloc] init];
      config.rfidTagsToFind  = [[NSArray alloc] initWithObjects:@"1ABE1C0DE00000000000001B", nil];
      [self.flomioSDK setConfiguration:config];

     let config = FmConfiguration.init()
     config.rfidTagsToFind = ["1ABE1C0DE00000000000001B"]
     self.flomioSDK.configuration = config

Classes and Methods (Deprecated)


Add FmSessionManagerDelegate to receive scan events and reader status changes.

Here is a quick summary of the notifications your app will receive from the Flomio SDK.

Delegate Method Description
didFindTag Returns a FmTag object when a tag has been detected from the reader
didChangeStatus Returns readers CommunicationStatus along with other reader info
didGetLicenseInfo When using the basic SDK, this connected displays whether the reader is licensed
didChangeCardStatus Returns a CardStatus object when a tag has entered/left the readers range
didReceiveReaderError Returns an error if there is a problem with the device


Method Parameters Description
startReaders Enable paired or connected readers to begin polling for tags. This can mean different things depending on PowerOperation setting.
stopReaders Disable paired or connected readers from polling for tags. This can mean different things depending on PowerOperation setting.
sleepReaders Put FloBLE Plus reader to sleep. This will also configure the reader to sleep after 60 seconds.
sendApdu toDevice success APDU String, deviceId: String, completionBlock Send an APDU using your connected device.
updateCeNdef withDeviceUid ndef: FmNdefMessage, deviceId: String Configure your FloBLE Plus to emulate a tag with new NDEF data. Use when FmConfiguration’s isCeMode is true.


You must first configure your settings and initialize the SDK.

Here is a description for each configuration item, some items are not relevant for some readers.

FmConfiguration Type Description
deviceType DeviceType Choose your device type, you may only use one device type at a time.
scanSound Boolean Hear notifications from Flojack MSR.
scanPeriod Number Period of polling for Audiojack readers (ms).
powerOperation PowerOperation Determine power operation for FloBle Plus. The affects how startReader and stopReader control your FloBle Plus, either control bluetooth for low power operation or nfc polling for standard use.
transmitPower TransmitPower Control the power of the NFC polling on the FloBle Plus.
allowMulticonnect Boolean Control whether multiple FloBLE devices can connect simultaneously.
specificDeviceUid String Use the device id from back of device (or deviceId property) to only connect to a certain bluetooth reader. This is only for use when ‘Allow Multiconnect’ = @0.
isCeMode Boolean Activates Card Emulation mode on FloBLE Plus
rfidTagsToFind Array Array of strings to indicate the identifiers of the RFID tags you want to target with your uGrokit UHF RFID reader.

Note: Booleans listed are NSNumber initialized with Booleans. Use @YES/@No in Objective-C and true/false in Swift


This is returned when a tag is tapped from the didFindTag:tag fromDevice:deviceId delegate method on FmSessionManagerDelegate


FmTag Type Description
atr String The ATR can be used to determine the type of tag.
uid String The Unique Identifier of the tag.


Method Parameters Description
readNdef completionBlock Returns the FmNdefMessage read from the tag in a completion block
writeNdef FmNdefMessage, completionBlock Pass a NDEF message to write, returns boolean to indicate whether tag was written successfully



Represents an NDEF (NFC Data Exchange Format) data message that contains one or more FmNdefRecords.

Name Type Description
ndefRecords Array of FmNdefRecords An array of FmNdefRecords.
error Error Will explain the reason if there was a problem reading/parsing the data on the tag.



Represents a NDEF (NFC Data Exchange Format) record as defined by the NDEF specification.

Name Type Description
tnf Number The Type Name Format field of the payload.
type Data The type of the payload.
id Data The identifier of the payload
payload Data The data of the payload
url URL? An optional convenience parameter which will return the payload as a URI for URI records.



Name Type Default Description
kFlojackBzr Number 1 FloJack BZR
kFlojackMsr Number 2 FloJack MSR
kFloBleEmv Number 3 FloBLE EMV
kFloBlePlus Number 4 FloBLE Plus
uGrokit Number 5 uGrokit / Flojack Gen 2



Parameter of FmConfiguration for configuring the power of FloBLE Plus.

Name Type Default Description
AutoPollingControl Number 0 startReaders and stopReaders turns on/off the reader from polling.
BluetoothConnectionControl Number 1 startReaders and stopReaders turns on/off bluetooth, this can be used when exiting from/returning to your app.



This is returned when there is a status update from the didChangeStatus delegate method on FmSessionManagerDelegate

Name Type Default Description
Scanning Number 0 The device is connected and scanning for tags.
Connected Number 1 The device is connected to bluetooth but not scanning for tags.
Disconnected Number 2 The device is disconnected from bluetooth and not scanning for tags.



This is returned when when a tag has entered/left the readers range from the didChangeCardStatus delegate method on FmSessionManagerDelegate

Name Type Default Description
NotPresent Number 0 A tag is not in range of the reader
Present Number 1 A tag is in range of the reader.



Parameter of FmConfiguration Used to determine the strength of the FloBLE Plus’s transmit power.

Name Type Default Description
VeryLowPower Number 0 Lowest power setting
LowPower Number 1
MediumPower Number 2
HighPower Number 3 Highest power setting


Please visit the forums for help and to see previous questions.

Unsupported Architecture

When submitting to the App Store, if you get the Error ERROR ITMS-90087: Unsupported Architecture. Your executable contains unsupported architecture '[x86_64, i386]'." Add a Run Script step to your build steps, put it after your step to embed frameworks, set it to use /bin/sh and enter the following script:


 # This script loops through the frameworks embedded in the application and
 # removes unused architectures.
 find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
     FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
     echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"


     for ARCH in $ARCHS
         echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"

     echo "Merging extracted architectures: ${ARCHS}"
     lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
     rm "${EXTRACTED_ARCHS[@]}"

     echo "Replacing original executable with thinned version"


credit: Daniel Kennett

Android Integration (Deprecated)

NFC Actions & IFTTT (Deprecated)

The recently revamped NFC Actions app is now available in the App Store. 🎉🍾🥂

Use your FloBle Plus to write and read NFC tags (specifically Mifare Ultralight tags).

It also works with IFTTT so you can use NFC to automate your daily routine or prototype your NFC start-up without needing a front end app!

For example, with IFTTT combined with NFC Actions, you can log employees time and attendance, you can monitor inventory or control smart devices with a tap!

Set up your IFTTT

Create IFTTT Account

First, you obviously need a IFTTT account.

Get Maker Webhook URL

Then you’ll need to go to get your Maker Webhook URL from the Maker Webhook settings. First connect Maker Webhooks and then copy your Maker URL which should look like this:

Side note (optional): Navigate to your Maker URL to see details about how to make HTTP POST requests to trigger events.

Create your IFTTT Applet

You want to create your IFTTT Applet using Maker Webhooks to trigger your event… Sounds a lot more complicated than it is.

Go to IFTTT Create. Click “+this”, search 'Maker Webhooks’ and select it. Select 'Receive a web request’ and name your event to, for example, 'tag_scanned’.

Side note (optional): For more precise control, with a FloBLE Plus or FloBLE Noir, you can use the each tag Uid to trigger different events by setting the Event name to the Uid. This feature is not available when using native NFC on iOS as Apple do not allow access to Tag Uids.

Now click ’+that’, we will use iOS Calendar as an example here but you can use what you want. Click 'create a calendar event’. Now configure your event to show the details of the tag scan. Type 'Now’ into start time, click 'create’ and 'finish’.

Below are details of the values/'ingredients’ sent with the trigger.

IFTTT Ingredients

Ingredient Description
Value1 Tag Uid
Value2 Tag Location in Google Maps
Value3 Tag Payload (write to tag in NFC Actions to use this)

Paste the URL in NFC Actions

Now that you have your Maker URL and Maker Event Name, go to the NFC Actions app and navigate to settings and paste them into the IFTTT settings fields.

Frequently Asked Questions

Can the SDK run in the background? We don’t expect Apps to ever be able operate FloJacks in the background. The FloJack requires a heartbeat handshake in order to prevent it from going into sleep mode and it’s not possible to handle from background. The active/inactive methods in the ViewController are meant to wake/sleep the reader during foregrounding/backgrounding. The FloBLE products are able to operate from a backgrounded app state. Also several of the same FloBLE products can connect to the iOS device at once (max 7 connected FloBLEs at a time).
What’s the difference between the Basic SDK and the Pro SDK? The Flomio SDK is currently sold on the per device license. That means that if you build an app with the Flomio SDK it will only work with readers that have valid licenses. Every FloJack and FloBLE reader we sell includes the Basic SDK license. This license is checked against reader device ID every time your app runs by checking our online database. That means that you need have web connectivity for the Basic SDK to work. For customers that need more flexibility, the Pro SDK is able to operate completely offline. The license is checked inside the Pro SDK bundle itself so you’re always guaranteed a good result.
Can I read and write NDEF data to tags with my reader? We recommend using the FloBLE Plus or FloBLE Noir to read and write data as the audio-jack data throughput is slow and unreliable. See FmTag for methods to read and write NDEF data.

Please visit the forums for help and to see previous questions.