Advanced

GDPR Export and Erase

Published · Last updated

When someone asks you to hand over or delete the personal data you hold about them (a data-subject access or erasure request under GDPR, the UK GDPR, CCPA and similar laws), you need to be able to find their chat data, export it, and remove it. This guide explains how to do that with Super Speedy Chat.

Available since 1.14.5.

Super Speedy Chat registers with WordPress’s own personal-data tools, so Tools > Export Personal Data and Tools > Erase Personal Data handle chat data for you. Enter the person’s email address on either screen and chat conversations are included alongside the data WordPress holds itself. The manual database steps further down are for requests those tools cannot match, such as a visitor who left only a phone number. For the wider picture of what is collected and why, read Privacy and Data Handling.

Using the WordPress tools

Export. Go to Tools > Export Personal Data, enter the address and send the request. The export a person receives includes, per conversation: the name, email address and phone number they gave, the channel, when it started and last ran, the page they were on, the referrer, their browser, their session token, and the full transcript with timestamps and who said what.

Erase. Go to Tools > Erase Personal Data, enter the address and confirm. Chat data is anonymised rather than deleted: the name, email address, phone number, browser, referrer, page address, WordPress account link and any channel identity (a WhatsApp number and profile name, for instance) are removed, and the conversation and its messages stay. That keeps your support history readable while taking the person out of it. If a request means the messages must go too, delete those conversations from the Chats screen, since the message text is the one place a person may have typed something about themselves that no automated rule can spot.

Both tools match on the address the visitor typed into the chat widget and on the WordPress account with that address, so a logged-in customer who never typed their address is still found. They cannot find a visitor who left only a phone number (see Contact Details to Ask For in Automated Responses and Canned Responses), or a WhatsApp visitor: find those by phone number with the query below and delete the conversation from the Chats screen.

Deleting a WordPress user anonymises their chat history the same way, so no conversation is left under an account that does not exist.

What personal data the plugin holds

Everything lives in your own database, in custom tables (see Backing Up and Migrating Chat Data for the full table list). The fields that count as a person’s personal data are:

  • Conversation record (ssc_conversations): visitor_name, visitor_email (only if the visitor entered it), user_agent, last_page_url, referrer_url, visitor_hash (their cookie token), user_id (if they were logged in), and anything stored in the metadata JSON column, which holds the phone number a visitor left on the contact prompt or a WhatsApp number (phone).
  • Participants (ssc_participants): display_name, plus the same visitor_hash and user_id links.
  • Messages (ssc_messages): the message text itself, in the message column.

Two more tables hold personal data only when a channel bridge is in use. ssc_discord_threads stores no personal fields itself (just conversation-to-thread ID mappings), and ssc_whatsapp_threads (added in the 1.11 series) stores wa_phone_number and wa_profile_name. The ssc_canned_responses table is your own saved replies, not visitor data, so it is out of scope for a subject request.

The ssc_visitor_hash cookie is the anonymous session identifier that ties a browser to its conversation. It is a random token, not derived from personal data, but because it links to a person’s messages it is treated as personal data here.

Finding a person’s data

There are four ways to locate someone, depending on what identifier you have. The quickest first pass is the search box on the Chats tab in wp-admin, which matches on visitor name and email. For a defensible, complete result, query the database directly. Adjust the wp_ prefix to match your install.

By email address:

SELECT id FROM wp_ssc_conversations WHERE visitor_email = 'person@example.com';

By WordPress user ID (for a logged-in visitor):

SELECT id FROM wp_ssc_conversations WHERE user_id = 123;

By phone number (as the visitor typed it, or a WhatsApp number with its leading +):

SELECT id FROM wp_ssc_conversations WHERE JSON_UNQUOTE(JSON_EXTRACT(metadata, '$.phone')) = '+44 7700 900123';

By cookie / session token, if the person can give you their ssc_visitor_hash value or you have it from logs:

SELECT id FROM wp_ssc_conversations WHERE visitor_hash = 'the-64-char-token';

Each query returns the conversation IDs that belong to that person. Keep that list; every later step keys off conversation_id.

Exporting the data

To produce an export, read the conversation rows and their child rows for the IDs you found. Run these as SELECTs and save the output (CSV or a SQL dump) to give to the requester:

SELECT * FROM wp_ssc_conversations WHERE id IN (10, 42);

SELECT * FROM wp_ssc_participants WHERE conversation_id IN (10, 42);

SELECT * FROM wp_ssc_messages WHERE conversation_id IN (10, 42);

If WhatsApp is in use and you are honouring a request for a WhatsApp visitor, also include their thread row:

SELECT * FROM wp_ssc_whatsapp_threads WHERE conversation_id IN (10, 42);

The messages query gives you the full transcript; the conversation query gives you the details (name, email, phone number in metadata, user agent, referrer, page URL; no IP address is stored). Between them they cover everything the plugin holds on that person.

Erasing the data

Best practice

Take a targeted mysqldump of the ssc_* tables before running any DELETE. The rows reference each other by conversation_id, and these deletions are permanent, so a backup is the only safe way to undo a mistake.

Back up first. Take a targeted dump of the chat tables before you delete anything, using the mysqldump command in Backing Up and Migrating Chat Data. Deletions here are permanent and the rows reference each other by ID, so a mistake is hard to undo without a backup.

Delete the child rows before the parent, so nothing is left orphaned. For the conversation IDs you identified:

DELETE FROM wp_ssc_messages     WHERE conversation_id IN (10, 42);
DELETE FROM wp_ssc_participants WHERE conversation_id IN (10, 42);
DELETE FROM wp_ssc_discord_threads   WHERE conversation_id IN (10, 42);
DELETE FROM wp_ssc_whatsapp_threads  WHERE conversation_id IN (10, 42);
DELETE FROM wp_ssc_conversations WHERE id IN (10, 42);

Include the Discord and WhatsApp lines only if those bridges are in use; they do no harm if the tables have no matching rows. After this, the person’s messages, metadata and channel mappings are gone.

If a lighter touch is enough (for example, the requester only wants their identifying details removed but you have a legitimate reason to keep the anonymised transcript), you can instead blank the personal fields rather than deleting the whole conversation:

UPDATE wp_ssc_conversations
SET visitor_name = 'Removed', visitor_email = NULL, metadata = NULL,
    user_agent = NULL, referrer_url = NULL, last_page_url = NULL
WHERE id IN (10, 42);

A caveat about deleting the plugin

Do not treat uninstalling the plugin as a way to service an individual request. Deleting Super Speedy Chat (not deactivating) runs its uninstaller, which drops all of the ssc_* tables and wipes every conversation for every visitor, not just the one you were asked about. Deactivation, by contrast, leaves all data in place. For a single subject request, always use the targeted DELETE statements above.

Common mistake

Never use “delete the plugin” to service one person’s erasure request. Deleting Super Speedy Chat runs its uninstaller and drops every ssc_* table, wiping all conversations for all visitors. Deactivating leaves everything in place. Only the scoped DELETE statements above remove one person’s data.

For endpoint details if you are scripting any of this against the plugin’s own API, see REST API Reference.

Further reading

what is collected, why, and where it is stored
the full table list and the mysqldump backup to take before erasing
endpoint details if you script a request against the plugin’s API

Comments

▲
▼
1/1