Appearance
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, optionalThe 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
