Ionic + Capacitor

Official @daertech/pushtifly-capacitor SDK on top of @capacitor/push-notifications, or integration via REST.

The official SDK @daertech/pushtifly-capacitor (Capacitor 8 or later) builds on @capacitor/push-notifications and adds what that plugin doesn't do:

  • device registration with an offline queue;
  • iOS environment detection (sandbox or production);
  • the Android channel;
  • notifications while the app is open, with buttons;
  • reported opens and clicks;
  • users, tags and topics.

Installation

npm install @daertech/pushtifly-capacitor @capacitor/push-notifications @capacitor/local-notifications
npx cap sync

@capacitor/local-notifications is optional: without it, notifications that arrive on Android while the app is open aren't shown, although they're still reported and reach onNotificationReceived.

  • Android: copy google-services.json into android/app/.
  • iOS: enable Push Notifications and Background Modes > Remote notifications in Xcode.

Show the notification while the app is open on iOS from capacitor.config:

{ "plugins": { "PushNotifications": { "presentationOptions": ["badge", "sound", "alert"] } } }

Usage

import { Pushtifly } from '@daertech/pushtifly-capacitor';

await Pushtifly.init({
  appKey: 'pk_live_YOUR_PUBLIC_KEY',       // PUBLIC key only
  environment: 'auto',                      // iOS: detected by the SDK
  androidChannel: { id: 'general', name: 'General notices' },
});

// Ask for permission once the user understands what it's for (not on app launch)
const state = await Pushtifly.requestPermission();   // 'granted' | 'denied' | ...

Pushtifly.identify('customer-123');          // on sign-in
Pushtifly.setTags({ plan: 'gold', city: 'NYC' });
Pushtifly.subscribe('offers');

Pushtifly.onNotificationOpened((n) => {
  // n.deepLink, n.actionId (tapped button), n.data (your data)
  if (n.deepLink) router.navigateByUrl(new URL(n.deepLink).pathname);
});

Pushtifly.logout();                          // on sign-out

Register onNotificationOpened when the app starts: if the app was opened from a notification, the SDK keeps that open and delivers it as soon as you subscribe.

Calls (identify, setTags, subscribe) don't wait for the network: they're stored in a persistent queue. They're sent as soon as there's a token and a connection, and retried with increasing backoff.

init options

Option Default Description
appKey — Public key pk_live_… or pk_test_…. The SDK rejects secret keys.
appId — Only if the key isn't restricted to one app.
environment auto sandbox or production to force it on iOS.
autoRegister false Ask for permission at launch.
foregroundDisplay true Show notifications while the app is open.
androidChannel — Channel the SDK creates; it must match the app's default channel in Pushtifly.
iosNotificationServiceExtension false The app includes the extension (see below); enables images and buttons on iOS.
apiUrl https://api.pushtifly.com Only for testing.
debug false Logs in the console.

Test device

In Devices, the panel shows a 6-digit pairing code; in the app:

await Pushtifly.pairTestDevice('483920');

Images and buttons on iOS

iOS only shows media and buttons if the app includes a Notification Service Extension. The SDK ships one ready to use:

  1. In Xcode (ios/App): File > New > Target > Notification Service Extension.
  2. Replace the generated NotificationService.swift with node_modules/@daertech/pushtifly-capacitor/ios/NotificationService/NotificationService.swift.
  3. Start the SDK with iosNotificationServiceExtension: true.

On Android, images and buttons work with no extra steps.

On Android a send with a carousel shows as a notification with the first image (no extra steps). On iOS it can be shown in full:

The carousel needs, besides the Service Extension, a Notification Content Extension:

  1. In Xcode: File > New > Target > Notification Content Extension.
  2. Replace its NotificationViewController.swift and Info.plist with the package's: node_modules/@daertech/pushtifly-capacitor/ios/NotificationContent/. Delete the generated MainInterface.storyboard.
  3. Also use the updated Service Extension template (node_modules/@daertech/pushtifly-capacitor/ios/NotificationService/): it downloads all the images.
  4. Start the SDK with iosNotificationServiceExtension: true and iosNotificationContentExtension: true.

On long press the carousel appears; the View button opens the app with the visible image's link.

What the SDK reports

Event When
received The notification arrives while the app is open.
opened The user taps the notification.
clicked The user taps a button (includes actionId).
permission_granted / permission_denied The permission changes.

You see them in each send's details and in the app's integration status.

Without the SDK (REST)

If you use another plugin, register the token yourself with POST /v1/devices:

await fetch('https://api.pushtifly.com/v1/devices', {
  method: 'POST',
  headers: { Authorization: 'Bearer pk_live_YOUR_PUBLIC_KEY', 'Content-Type': 'application/json' },
  body: JSON.stringify({ token, platform: Capacitor.getPlatform(), environment: 'auto', framework: 'capacitor' }),
});

The send's id arrives in data._phid and the link in data.deepLink. Report it to /v1/events on open.