npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pushapp-ionic

v0.2.0

Published

PushApp Capacitor plugin for push notifications and in-app messaging

Readme

PushApp-Ionic SDK

Capacitor 7 plugin for push notifications, in-app messaging (popup, banner, roadblock, inline, tooltip), event tracking, and session handling in Ionic/Capacitor apps (iOS + Android).

Documentation site: https://docs.mehery.com/guide/pushapp/ionic-sdk/ — hosted on MeherY docs; HTML source in this repo under docs-site/ (see docs-site/README.md).

Start here

| I want to… | Read this | |------------|-----------| | Integrate the SDK into my Ionic app | Integration Guide — follow sections 1–9 in order | | See a working app | example-app/ — copy pushapp-setup.ts first | | Look up a method | API reference below · docs/api-reference.md | | Test before production | QA Test Plan | | Handle errors in code | Error handling below |

New to Capacitor? Allow 2–4 hours. Test on a real device — push does not work in the browser.


When to call what

| When | Call | Where in your app | |------|------|-------------------| | App launches (before login screen) | initialize() then register() | app.component.ts or pushapp-setup.ts | | User signs in | login() then saveUserData() | Login success handler — await login() (device link) before saveUserData() | | User signs out | logout() | Logout handler (before clearing auth) | | User returns with saved session | initialize()register()login() | App launch (see Integration Guide §5C) | | Screen opens | setPageName() + sendEvent() | Page ionViewDidEnter | | Inline campaign slot on screen | registerPlaceholder() / unregisterPlaceholder() | Page enter / leave | | Tooltip campaign anchor | registerTooltipTarget() / unregisterTooltipTarget() | Page enter / leave | | Host app owns FCM (own service / Firebase Messaging plugin) | handlePushNotification() | Forward received payloads so the SDK can show tray / in-app |

Lifecycle order (required): initialize()register()login()

Full code and file paths: Integration Guide §5


Quick checklist

Your app should include:

  • Firebase config: android/app/google-services.json and/or ios/App/GoogleService-Info.plist
  • Android Gradle: google-services plugin applied — see Integration Guide §3b
  • iOS: Firebase/Messaging pod, Push Notifications capability, AppDelegate (APNs + FCM + notification taps) — see Integration Guide §3–4
  • SDK calls in order: initialize()register()login() (call logout() on sign-out)
  • After login (when needed): saveUserData({ code: userId, … }), setPageName(), sendEvent()
  • iOS notification tap tracking — see Integration Guide §4b
  • If another plugin owns FCM: forward with handlePushNotification() — see Host-owned FCM
  • Inline/tooltip registration only if your PushApp campaigns use those surfaces

register() is safe to call on every app open — the native SDK avoids duplicate registration when the device is already registered with the same push token. If the token changes later, the SDK updates it automatically after the first successful registration. After logout(), the SDK clears local registration state and registers again as a fresh guest device.

login() resolves only after /device/link succeeds. Call saveUserData() afterward with code: userId (not userId_deviceId). Customer profiles are not updated automatically.


Setup (overview)

Full steps with file paths and native config: Integration Guide

  1. Installnpm install pushapp-ionic (+ optional @capacitor/push-notifications or @capacitor-firebase/messaging if your app owns FCM) + npx cap sync
  2. Firebase — add config files (Guide §3)
  3. Native — iOS AppDelegate + Android Gradle (Guide §3–4)
  4. App launchinitialize() + register() (Guide §5A–B)
  5. After login — await login() + saveUserData({ code: userId, … }) (Guide §5C, §6)
  6. Per screensetPageName() / sendEvent() (Guide §7)

Recommended: copy example-app/src/app/pushapp-setup.ts into your project.

import { PushApp } from 'pushapp-ionic';
import { environment } from '../environments/environment';

await PushApp.initialize({
  appId: environment.pushApp.appId, // required — channel id (tenant_suffix)
  // Optional API credentials (sent as x-app-id / x-app-key when provided):
  pushAppId: environment.pushApp.pushAppId,
  appSecretKey: environment.pushApp.appSecretKey,
  sandbox: environment.pushApp.sandbox,
  debugMode: !environment.production && environment.pushApp.debugMode,
});
// then register() — see pushapp-setup.ts

Configuration

Store credentials in environment files — do not hardcode in components:

// src/environments/environment.ts
export const environment = {
  production: false,
  pushApp: {
    appId: 'yourtenant_1234567890', // required — channel id
    pushAppId: 'pa_…', // optional — PushApp API App Id (x-app-id)
    appSecretKey: 'pas_…', // optional — PushApp App Secret Key (x-app-key)
    sandbox: true,
    debugMode: true, // dev only — verbose native logs (tokens redacted)
  },
};

Do not pass slackWebhookUrl in production (integration debugging only).


Environments

Use the sandbox flag provided with your PushApp credentials:

| sandbox | Environment | |-----------|-------------| | false | Production | | true | Sandbox / testing |


Web / browser

Browser dev: This plugin is native-only. In ionic serve, methods return WEB_NOT_SUPPORTED. Use Capacitor.isNativePlatform() before placeholder/tooltip calls. Test push on a real device.


Inline placeholders

Use when PushApp campaigns deliver inline content into your app UI. The SDK automatically tracks placeholder position on scroll (including Ionic ion-content), resize, and fixed headers (ion-header).

<div id="promo-banner" class="promo-slot"></div>
// ionViewDidEnter
await PushApp.registerPlaceholder({ placeholderId: 'promo-banner' });

// ionViewWillLeave
await PushApp.unregisterPlaceholder({ placeholderId: 'promo-banner' });

Full details: Integration Guide §8


Host-owned FCM (optional)

Android delivers each FCM message to only one FirebaseMessagingService. If your app (or @capacitor-firebase/messaging / @capacitor/push-notifications) owns FCM, the SDK’s native service will not receive messages unless you forward them:

  1. Keep a single FCM owner in the merged manifest (strip competing MESSAGING_EVENT filters if needed).
  2. On receive, call:
await PushApp.handlePushNotification({
  title: notification.title,
  body: notification.body,
  data: notification.data ?? {},
});

See example-app/src/app/pushapp-setup.ts for a Capacitor Firebase Messaging listener pattern.


Tooltip targets

Register anchor elements for native tooltips. Register in ionViewDidEnter after DOM layout (requestAnimationFrame / short setTimeout). targetId must match your PushApp campaign config.

const el = document.getElementById('deals-fab');
const rect = el!.getBoundingClientRect();

await PushApp.registerTooltipTarget({
  targetId: 'center', // campaign target id
  x: Math.round(rect.left),
  y: Math.round(rect.top),
  width: Math.round(rect.width),
  height: Math.round(rect.height),
});

await PushApp.unregisterTooltipTarget({ targetId: 'center' });

Full details: Integration Guide §8


API reference

Core

| Method | When to call | |--------|----------------| | initialize({ appId, pushAppId?, appSecretKey?, sandbox?, debugMode?, slackWebhookUrl? }) | App startup — appId required; pushAppId / appSecretKey optional | | register({ fcmToken?, apnsToken?, token? }) | After initialize — both platforms; pass empty fcmToken to use native cached tokens (recommended — see pushapp-setup.ts) | | login({ userId }) | After register, when user signs in — resolves after device link succeeds | | logout() | On sign-out — clears local session and delinks device on server | | saveUserData({ code, additionalInfo, cohorts }) | After successful login()code is userId (not userId_deviceId) | | setPageName({ pageName }) | On screen change | | sendEvent({ eventName, eventData }) | On user actions | | getDeviceHeaders() | Anytime | | trackPushNotificationEvent({ token, event, ctaId? }) | Notification open / CTA tap¹ | | handlePushNotification({ title?, body?, data? }) | When the host app owns FCM — forward payload for tray / in-app |

¹ Requires native notification handler — see Integration Guide §4b. Android handles taps via the SDK's NotificationClickReceiver when the SDK owns FCM.

Inline & tooltip

| Method | When to call | |--------|----------------| | registerPlaceholder({ placeholderId, elementId?, clipTopSelector? }) | View enter | | unregisterPlaceholder({ placeholderId }) | View leave | | registerTooltipTarget({ targetId, x, y, width, height }) | View enter | | unregisterTooltipTarget({ targetId }) | View leave |

Auto-generated details: run npm run docgendocs/api-reference.md


Error handling

Native methods reject with stable code values (e.g. NOT_INITIALIZED, REGISTER_FAILED, EMPTY_TOKEN). Import helpers from the package:

import { PushApp, PushAppErrorCode, getPushAppErrorCode, isPushAppError } from 'pushapp-ionic';

try {
  await PushApp.register({ fcmToken: '' });
} catch (err) {
  if (getPushAppErrorCode(err) === PushAppErrorCode.EMPTY_TOKEN) {
    // retry when token arrives — see pushapp-setup.ts
  }
}

Common codes: Integration Guide §13


Platform notes

Android

  • Minimum API 23 (Android 6.0)

  • Android 13+: notification permission is requested by the SDK on initialize() — user must tap Allow

  • ProGuard (release): add to android/app/proguard-rules.pro:

    -keep class com.mehery.pushapp.** { *; }
  • Gradle: google-services plugin required — see Integration Guide §3b

iOS

  • Minimum iOS 15.2 (match platform :ios in Podfile)
  • Enable Push Notifications capability in Xcode
  • Add pod 'Firebase/Messaging' to ios/App/Podfile, then pod install
  • AppDelegate: Firebase init, forward APNs token to Firebase + PushApp, handle FCM refresh, notification tap tracking — see Integration Guide §4
  • Reference: example-app/ios/App/App/AppDelegate.swift

Example app

Run the demo:

cd example-app && npm install && npx cap sync

| File | What to copy | |------|----------------| | src/app/pushapp-setup.ts | initialize + register (+ optional Firebase Messaging forward) | | src/app/login/login.page.ts | login + saveUserData({ code: userId }) | | src/app/home/home.page.ts | setPageName, placeholders, tooltips, logout | | ios/App/App/AppDelegate.swift | Firebase + APNs + FCM refresh + notification tap tracking |

This is the canonical integration pattern — prefer it over ad-hoc snippets.


Troubleshooting

| Issue | What to check | |-------|----------------| | initialize fails | App ID format: tenant_suffix (e.g. demo_1763369170735) | | register rejected | Call initialize() first; token may not be ready on first launch — use retry pattern from pushapp-setup.ts | | Token refresh / new FCM | Handled natively after first successful register when the SDK owns FCM — no extra JS needed | | login rejected | Call register() successfully first; check network / credentials | | saveUserDataDEVICE_LINK_REQUIRED | Await successful login() first; use code: userId | | No push / SDK not showing tray | Real device; Firebase config; if another app FirebaseMessagingService owns FCM, forward with handlePushNotification() | | Testing in browser | Expected: WEB_NOT_SUPPORTED — use a device | | After logout, push tied to old user | Call logout() before clearing local auth | | Inline never shows | placeholderId mismatch; register after DOM ready; call setPageName / sendEvent | | Inline stuck while scrolling | Ensure you are on a build with Ionic ion-content scroll sync; re-register on view enter | | Inline overlaps header | Ensure clipTopSelector matches your fixed header (default: ion-header) | | Parse errors in catch | Use getPushAppErrorCode(err) instead of parsing message strings |

Logs: Android Logcat / iOS Xcode console → filter PushApp (use PushApp:D on Android for debug logs)


Development (SDK maintainers)

npm install
npm run lint      # ESLint + Prettier + SwiftLint
npm run build
npm test          # TypeScript unit tests (Node 18+)
npm run test:contract  # verify error codes match across TS / Kotlin / Swift
npm run verify    # build + Android tests + SwiftLint

CI: .github/workflows/ci.yml · Release: CHANGELOG.md · docs/RELEASE.md


Version

Current version: 0.2.0 — see CHANGELOG.md and docs/RELEASE.md.


Support


License

MIT