Skip to content

Install tracking

Wire your plugin's register_activation_hook and register_deactivation_hook to PackEdge so the Analytics → Installs/Uninstalls tab shows:

  • Install and uninstall trends over time
  • PHP / WordPress / MySQL / OS / server-software breakdowns
  • memory_limit, locale, multisite flag
  • Active theme on customer sites
  • Top sibling plugins installed alongside yours
  • Top uninstall reasons + verbatim feedback

You don't need a PHP SDK — a single REST POST to /public/v1/event carries everything.

Payload shape

json
{
  "public_key": "pk_your_public_key",
  "event": "product.installed",
  "license_key": "MYPLUGIN-XXXX-XXXX-XXXX-XXXX",
  "site": "shop.example.com",
  "properties": {
    "env": {
      "php": "8.1.27",
      "wp": "6.4.2",
      "os": "linux",
      "server": "nginx/1.24.0",
      "mysql": "8.0.36",
      "memory_limit": "256M",
      "locale": "en_US",
      "multisite": false,
      "theme": { "name": "twentytwentyfour", "version": "1.1" }
    },
    "plugins": ["woocommerce", "yoast-seo", "wp-rocket"]
  }
}

For product.uninstalled, add two more keys at the top of properties:

jsonc
"reason":   "switching",                    // short, machine-readable
"feedback": "Moving to a competitor with better docs"  // free-text, optional

The dashboard groups by reason, so use a small enum (switching, no_longer_needed, too_complicated, buggy, missing_feature, temporary, other) instead of arbitrary strings.

Drop-in PHP

Save in your plugin's main file. Replace pk_your_public_key and the myplugin_ prefix with your product's key and your plugin slug.

php
<?php
// Track install + uninstall in PackEdge.
register_activation_hook(__FILE__, 'myplugin_track_install');
register_deactivation_hook(__FILE__, 'myplugin_track_uninstall');

function myplugin_env_snapshot() {
  global $wp_version, $wpdb;
  $theme = wp_get_theme();
  // The active-plugins list is sensitive per-site config. Remove this line
  // (or pass an empty array) if your privacy policy doesn't allow it.
  $plugins = array_map(fn($p) => dirname($p), get_option('active_plugins', []));
  return [
    'env' => [
      'php'          => PHP_VERSION,
      'wp'           => $wp_version,
      'os'           => strtolower(PHP_OS_FAMILY),
      'server'       => $_SERVER['SERVER_SOFTWARE'] ?? '',
      'mysql'        => $wpdb->db_version(),
      'memory_limit' => WP_MEMORY_LIMIT,
      'locale'       => get_locale(),
      'multisite'    => is_multisite(),
      'theme'        => [
        'name'    => $theme->get_template(),
        'version' => $theme->get('Version'),
      ],
    ],
    'plugins' => $plugins,
  ];
}

function myplugin_post_event($event, $extra = []) {
  $properties = array_merge(myplugin_env_snapshot(), $extra);
  wp_remote_post('https://api.packedge.dev/public/v1/event', [
    'headers'  => ['Content-Type' => 'application/json'],
    'blocking' => false, // never block the install / uninstall
    'body'     => json_encode([
      'public_key'  => 'pk_your_public_key',
      'event'       => $event,
      'license_key' => get_option('myplugin_license_key', ''),
      'site'        => parse_url(home_url(), PHP_URL_HOST),
      'properties'  => $properties,
    ]),
  ]);
}

function myplugin_track_install() {
  myplugin_post_event('product.installed');
}

function myplugin_track_uninstall() {
  myplugin_post_event('product.uninstalled', [
    'reason'   => sanitize_text_field($_POST['reason']   ?? ''),
    'feedback' => sanitize_textarea_field($_POST['feedback'] ?? ''),
  ]);
}

Capturing the uninstall reason

A common pattern is to intercept the deactivation flow with a small modal that asks "why are you removing this plugin?" and POSTs reason / feedback to your own AJAX endpoint, which then calls myplugin_track_uninstall() before allowing the deactivation to proceed. The Console will show the reason in the Uninstall reasons panel and the free-text in the Recent feedback panel.

JavaScript SDK

If you'd rather use the SDK (e.g. for SPAs or Gutenberg blocks):

ts
import packedge from '@packedge/js-sdk';

packedge.init('pk_your_public_key', { licenseKey: '…' });

packedge.track('product.installed', {
  env: { php: '…', wp: '…', os: 'linux', /* … */ },
});

packedge.track('product.uninstalled', {
  reason: 'switching',
  feedback: 'Moving to a competitor with better docs',
  env: { /* … */ },
});

Privacy

  • The active-plugins list reveals a customer's other paid plugins and is competitive intel. Respect end-user consent. Hash, trim, or omit it if in doubt.
  • PHP / WP / OS / server / MySQL versions, memory limit, locale, and the multisite flag are configuration metadata and generally safe to send.
  • Theme slug + version are usually fine to send.
  • Free-text feedback is whatever the customer types. Don't auto-collect it without an opt-in prompt.

Where it shows up

Console → product → Analytics → Installs/Uninstalls:

  • Summary cards (totals + net change + top domain)
  • Install / Uninstall trend charts
  • Uninstall reasons bar list + filterable
  • Recent feedback verbatim feed
  • Environment grid (8 dimensions)
  • Active themes + Sibling plugins lists
  • Top install domains