Skip to content

Deleting User data🔗

According to the GDPR law, the user can request to delete their user data from the systems. In order to do this, the user has several ways: Delete data through the support widget or Delete data by button.

Procedure for deleting user data🔗

With any approach (through the support widget window, or by clicking a button), when the created request (ticket) goes into operation, the following steps are performed:

  1. User data is manually checked based on support data and the project GMTool to exclude malicious deletion of user data (whether he personally made the request, whether he really wanted it, etc.).
  2. Support operators manually delete/block players in the GMTool of the project (or projects if the removal of the MyGames account was requested).
  3. Support operators creates tasks for a project to completely delete the user.
  4. After the user is successfully deleted, the data is deleted from the third-party systems used (MRGS, 1Link) by setting tasks.

For more details about each step and a detailed description of the deletion logic, see in the MyGames Support documentation

Delete data through the support widget🔗

If a player wants to delete his data, he needs to create a request from the corresponding article on the support site or in the mobile widget. Example article.

After that, the support staff contacts the user, clarifies all the details, and begins the removal process described above

Deleting data by button🔗

In accordance with the requirement of the AppStore, from February 2022 on projects where there is an account creation, the user should be able to initiate the process of deleting his account by simply pressing a button in the application interface.

Access to such functionality can have a number of negative consequences for both the user and the project - accidental clicking, clicking by another person, respectively, it is highly desirable to provide for the possibility of canceling the decision to delete by the user. The period during which the user can cancel the request independently can be obtained when creating a ticket via the API in the cancel_to field, or contact support contact person. After the expiration of the period for self-cancellation, the user's account will be blocked manually by the support service. After that, the internal account deletion process described above will be launched.

Recommendations for implementing interface solutions that meet the AppStore requirement to provide users with a simple account deletion functionality.
  1. Clicking the delete button should trigger additional warnings (for example, «Are you sure you want to delete the account, including all achievements and all progress?»).
  2. After activating the delete button, the user must be given several days to cancel the process independently, for example, by transforming the delete button into a cancel button or by introducing an additional interface element with a similar function.
  3. After clicking the delete button, noticeable information should appear in the interface that account deletion has been requested. This can be implemented through displaying the «Account deletion started» bar on top of the interface, through blocking the interface, through the appearance of an additional notification screen before launching the application.
  4. After the expiration of the period for self-cancellation, the user will be blocked by support staff, and so that the user does not have any questions about the reasons for blocking, it is worth providing a special information window with the reason for blocking, which will be displayed to the user when trying to launch the application. Example - «You requested account deletion. The process of deleting an account takes some time. During this period, the account will be blocked.».

The MyGames Support server API for creating and canceling user data deletion requests is described in the MyGames Support documentation, but we recommend using the MRGS server and client API described below, because:

  1. You will not have to get additional secret keys, and most likely you have already configured integration with MRGS.
  2. Our API solves some problems of synchronization of cancellation of requests between different platforms, and other possible problems, see below for more details.

Important note about synchronization

Although the requirement to delete an account by a button is put forward only on iOS, if the application supports synchronization on different platforms or devices, then the account deletion status must also be synchronized so that the user can see everywhere that his account is in the process of deletion and can cancel the request from any of the devices.

Creating a deletion request🔗

To create a deletion request, you can use either the server or client API:

Using the server API

To create a deletion request, use the /support/deleteProfile/ API.

In response, you will receive a dictionary containing a unique ticket identifier for all projects, the time of its creation, as well as the time before which the user can cancel it.

Using the client SDK

To request the deletion of user data, you need to call the method:

MRGSMyGamesSupport.Instance.RequestAccountDeletion((ticket, error) =>
{
    if (error == null)
    {
        Debug.Log("MRGSMyGamesSupport#RequestAccountDeletion success: " + ticket);
    }
    else
    {
        if (error.Code == (int)MRGSMyGamesSupportError.NetworkError)
        {
            Debug.Log("Network error, try again later");
        }
        else
        {
            Debug.Log("MRGSMyGamesSupport#RequestAccountDeletion failed: " + error.Description);
        }
    }
});

// Async/await way
var (ticket, error) = await MRGSMyGamesSupport.Instance.RequestAccountDeletionAsync();
var ticket = await MRGSMyGamesSupport.Instance.RequestAccountDeletionAsync().Throwable();
[[MRGSMyGamesSupport sharedInstance] requestAccountDeletionWithCompletionHandler:^(MRGSMyGamesSupportTicket * _Nullable ticket, NSError * _Nullable error) {
    if(!error){
        NSLog(@"Created request: %@", [ticket description]);
    }else{
        if(error.code == MRGSMyGamesSupportErrorNetworkConnectionFailed){
            NSLog(@"Network error, try again later");
        }else{
            NSLog(@"Received error - Code: %lu; Description: %@", error.code, error.localizedDescription);
        }
    }
}];
import androidx.annotation.Nullable;

import games.my.mrgs.MRGSError;
import games.my.mrgs.support.MRGSMyGamesSupport;
import games.my.mrgs.support.MRGSMyGamesSupportTicket;
import games.my.mrgs.utils.optional.BiConsumer;

MRGSMyGamesSupport.getInstance().requestAccountDeletion(new BiConsumer<MRGSMyGamesSupportTicket, MRGSError>() {
    @Override
    public void accept(@Nullable MRGSMyGamesSupportTicket ticket, @Nullable MRGSError error) {
        if (error == null){
            Log.d("MRGSMyGamesSupport", "RequestAccountDeletion success: " + ticket);
        } else {
            if (error.getErrorCode() == MRGSMyGamesSupport.NETWORK_ERROR){
                Log.d("MRGSMyGamesSupport", "Network error");
            } else {
                Log.d("MRGSMyGamesSupport", "RequestAccountDeletion failed: " + error.getErrorText());
            }
        }
    }
});

In response, you will receive an object MRGSMyGamesSupportTicket containing a unique ticket identifier for all projects (which is important to save on the project server as an additional confirmation of the user's action), the time of its creation, as well as the time before which the user can cancel it.

In case of an error (for example, there is no Internet, the MRGS server or support is unavailable), we recommend that you show the corresponding window to the user. Possible error codes and tips for handling them are listed in section below.

Duplication of data on the project server

Since the client can be hacked, and the account deletion procedure is not reversible to a certain extent, it is very important to duplicate the logs in the admin panel/GMTool by clicking the button to delete and cancel the account deletion, so that the support service after receiving the ticket can verify in the admin panel/GMTool that such a process was really initiated by the user, and not forged. It is also desirable that the support service in GMTool should be able to choose the reason for blocking, or a separate button for blocking at the time of account deletion, so that the user can see the reason for blocking in the interface (see the recommendations for implementing the interface above).

Why not just store all the data on MRGS servers and force projects to store it on their servers?

As a rule, games/applications have a kind of user authorization system to protect against account theft. Therefore, all the logged actions of such users are considered more reliable. MRGS does not have a user authorization system, so storing such data, for example, information that the user requested deletion, on the MRGS side, there is no way to somehow validate this user that it was really him. So, such data needs to be stored on the project servers, and it is on this data that the support service will rely using the GMTool of the project.

What happens after pressing the button?

After creating a deletion request via the API, an invisible ticket is created for the user, which is placed in the queue for X days (see the number of days at the beginning of the section. The ticket itself is visible to the support staff and can be found through ticket search, but is not taken into operation), during which the user can cancel it, after this time the ticket is automatically removed from the queue and goes to the "open" status, after that it is taken to work by support staff, and the account deletion becomes irreversible.

Cancellation of the deletion request🔗

Within X days, the request to delete data can be canceled, the value of this interval you receive when creating a ticket.

Nuances of request cancellation

If the application supports synchronization on different platforms or devices, the user can cancel the request from another device/platform. For example, the request is initiated from an iOS project, but the user can cancel it from Android. In this case, when creating the request, one projectID (iOS) was used and another (Android) was used to delete it, and for the support system these are two unrelated projects with their own userIds. Therefore, when using the MyGames Support API directly, you will have to cancel the request for each of the projects in the loop. When using MRGS, this will not have to be done (see below).

To cancel the deletion request, you can use either the server or client API:

Using the server API

To create a deletion request, use the /support/cancelProfileDeletionServer/ API.

This api allows you to cancel either for a specific project, or immediately for the entire group of projects (the fullProjectGroup field), if the project uses end-to-end user IDs and there is synchronization between platforms (see the clarification on the nuances of canceling the request above), and also allows you to exclude some projects when deleting across the entire project group (the `excludeProjectIds' field), in case some of them don't have end-to-end user IDs.

Thus, by making one API call, you can quickly cancel the data deletion requests.

Using the client SDK

To cancel the data deletion request, you need to call the method:

var ticketId = 123; // Received from server
MRGSMyGamesSupport.getInstance().CancelAccountDeletionRequest(ticketId, (error) =>
{
    if (error == null)
    {
        Debug.Log("MRGSMyGamesSupport#CancelAccountDeletionRequest success.");
    }
    else
    {
        if (error.Code == (int)MRGSMyGamesSupportError.TicketNotFound)
        {
            Debug.Log("No ticket is found, UI can be reset to normal.");
        } 
        else if (error.Code == (int)MRGSMyGamesSupportError.NetworkError)
        {
            Debug.Log("Network error, try again later");
        }
        else
        {
            Debug.Log("MRGSMyGamesSupport#CancelAccountDeletionRequest failed: " + error.Description);
        }
    }
});

// Async/await way
var error = await MRGSMyGamesSupport.Instance.CancelAccountDeletionRequestAsync(ticketId);
await MRGSMyGamesSupport.Instance.CancelAccountDeletionRequestAsync(ticketId).Throwable();
long ticketId = 123; // Received from server
[[MRGSMyGamesSupport sharedInstance] cancelAccountDeletionRequestForTicketId:ticketId withCompletionHandler:^(NSError * _Nullable error) {
    if(!error){
        NSLog(@"Cancelled request: %lu", ticketId);
    }else{
        if(error.code == MRGSMyGamesSupportErrorTicketNotFound){
            NSLog(@"No ticket is found, UI can be reset to normal.");
        }else if(error.code == MRGSMyGamesSupportErrorNetworkConnectionFailed){
            NSLog(@"Network error, try again later");
        }else{
            NSLog(@"Received error - Code: %lu; Description: %@", error.code, error.localizedDescription);
        }
    }
}];
import games.my.mrgs.MRGSError;
import games.my.mrgs.support.MRGSMyGamesSupport;
import games.my.mrgs.utils.optional.Consumer;

final long ticketId = 123; // Received from server
MRGSMyGamesSupport.getInstance().cancelAccountDeletionRequest(ticketId, new Consumer<MRGSError>() {
    @Override
    public void accept(MRGSError error) {
        if (error == null){
            Log.d("MRGSMyGamesSupport", "Cancelled request: " + ticketId);
        } else {
            if (error.getErrorCode() == MRGSMyGamesSupport.TICKET_NOT_FOUND){
                Log.d("MRGSMyGamesSupport", "No ticket is found");
            } else if (error.getErrorCode() == MRGSMyGamesSupport.NETWORK_ERROR){
                Log.d("MRGSMyGamesSupport", "Network error");
            } else {
                final String message = String.format("Received error - Code: %d; Description: %s", error.getErrorCode(), error.describeContents())
                Log.d("MRGSMyGamesSupport", message);
            }
        }
    }
});

Please note that cancellation requires the ID of the ticket, which was received when it was created, and which must be stored on the project server, this guarantees the security of the client method. This method will cancel the initial request, even if it is called from another platform, that is, if you create a request from iOS, get the ticket ID, and call this cancellation method from Android (with a different MRGS appId), the request will still be canceled.

In case of an error (for example, there is no Internet, the MRGS server or support is unavailable), we recommend that you show the corresponding window to the user. Possible error codes and tips for handling them are listed in section below.

Duplication of data on the project server

Recall that it is also desirable to duplicate all data on the cancellation of the request on the project server side, so that there are two points where data on user actions are stored for their verification.

Client error codes🔗

In case of an error (for example, there is no Internet, the MRGS server or support is unavailable), we recommend that you show the corresponding window to the user. Possible error codes:

Error Description Error code
User not set User not exposed in SDK MRGS 1010
Unknown Unknown error. Details can be found in the text of the error. 1020
Invalid input params Parameters passed incorrectly (for example, ticketId is empty) 1021
network error Network error 1022
Ticket not found The specified ticketId was not found in the support system 1023
Enum with error codes in IDE
public enum MRGSMyGamesSupportError
{
    UserNotSet = 1010,
    Unknown = 1020,
    InvalidParams = 1021,
    NetworkError = 1022,
    TicketNotFound = 1023,
}
typedef NS_ERROR_ENUM(kMRGSMyGamesSupportErrorDomain, MRGSMyGamesSupportErrorCode) {
    MRGSMyGamesSupportErrorUnknown = 1020,
    MRGSMyGamesSupportErrorUserNotSet = 1010,
    MRGSMyGamesSupportErrorInvalidParams = 1021,
    MRGSMyGamesSupportErrorNetworkConnectionFailed = 1022,
    MRGSMyGamesSupportErrorTicketNotFound = 1023,
};
public static final int ERROR_USER_NOT_SET = 1010;
public static final int ERROR_PROJECT_ID_INVALID = 1011;
public static final int UNKNOWN_ERROR = 1020;
public static final int INVALID_PARAMS = 1021;
public static final int NETWORK_ERROR = 1022;
public static final int TICKET_NOT_FOUND = 1023;

If the request received an error 1023 (Ticket not found), this means that such a ticket is not on the support server, that is, it could be canceled by the user, for example, through the support site. In this case, you can remove the inscription in the UI about the account deletion process and let the user into the application.

Testing data deletion at the user's request🔗

When creating a ticket through the API, it will be visible to support staff and can be found through ticket search even in the waiting queue, you need to check that when you click on the button, it is created, and when canceled, it is deleted. The complete removal procedure can be tested with support staff by running it for a test user.

Deletion of GDPR acceptance data🔗

After the user's account and his data are deleted, and the game client creates a new account for the user, it is necessary to show the user the screen again for accepting the GDPR terms. If you use MRGSGDPR module, then simply reset it to its original state. For more information, see Reset settings.


Last update: 2025-01-21
Created: 2022-01-24