Data Export in Mobile Apps: GDPR & Implementation

During an Apple app review, the build may be rejected if the data export feature is missing. <cite>GDPR Article 20</cite> mandates providing users with a copy of their data in a machine-readable, portable format. Without it, your app risks rejection from the App Store or Google Play. Over 9 years, w

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    597

During an Apple app review, the build may be rejected if the data export feature is missing. GDPR Article 20 mandates providing users with a copy of their data in a machine-readable, portable format. Without it, your app risks rejection from the App Store or Google Play. Over 9 years, we've implemented this feature in 50+ projects with loads up to 100,000 users. A typical problem: developers try to collect data synchronously in response to an HTTP request, leading to timeouts when the volume exceeds 1,000 records. Instead, we use an asynchronous pattern with a task queue and a temporary download link.

Which data to export and by what rules?

The minimum set under GDPR: all data that the user provided directly (profile, settings, content) and data created as a result of using the service (action history, transactions, preferences). Typically, the volume ranges from 500 to 10,000 records per user.

Data Type Include Example
User profile Yes Name, email, avatar
Settings Yes Language, theme, notifications
User content Yes Messages, orders, comments
Action history Yes Logins, purchases, views
Analytical aggregates No DAU, retention, ML weights
Server technical logs No IP, user-agent, access logs
Other users' data No Others' profiles, messages

Formats: JSON is preferred for machine-readability, CSV for users who want to open in Excel. A ZIP archive with multiple files is standard practice, as in Google Takeout. We specialize in GDPR-compliant mobile development, so we consider all data portability requirements.

Synchronous vs asynchronous export: which to choose?

Synchronous export is simpler to implement, but for volumes exceeding 5,000 records, it blocks the connection and causes timeouts. Asynchronous export is 10 times more reliable under high loads: it scales to 10 requests per minute without performance loss. API response time drops from 10–15 seconds to 200 ms, while full export takes 2–3 minutes—the user gets a notification when ready. Infrastructure savings: async export reduces peak loads, cutting server costs by up to 30%.

Feature Synchronous Asynchronous
API response time 5-15 sec <200 ms
Reliability for >5000 records Timeouts Stable
Database load High (peak) Smooth (queue)
User experience Waiting Polling + push

How to implement server-side export without blocking?

Export is a potentially heavy operation. A synchronous HTTP response for 10,000 records takes 5–10 seconds, exceeding the standard 30-second timeout. The correct solution is an asynchronous pattern with polling or webhook.

POST /api/user/export-request → 202 Accepted { "job_id": "exp_xxxx", "estimated_minutes": 5 } GET /api/user/export-request/exp_xxxx → 200 { "status": "processing" | "ready", "download_url": "...", "expires_at": "..." } 

A background task (Celery or Laravel Queue) collects data from all tables, generates an archive, uploads it to S3 with a presigned URL valid for 24–72 hours. After completion—push notification or email. Presigned URL with TTL is critical: never expose direct S3 links without authorization to avoid data leaks. In one project with 50,000 users, the async queue reduced the database load by 20 times compared to the synchronous approach.

Example Celery queue configuration For background processing we use Celery with Redis as broker. The export task looks like this:
@app.task(bind=True, max_retries=3, default_retry_delay=300) def export_user_data(self, user_id, job_id): try: user_data = collect_user_data(user_id) archive = create_zip_archive(user_data) presigned_url = upload_to_s3(archive, expires_in=86400) update_job_status(job_id, 'ready', presigned_url) send_push_notification(user_id, 'Export ready') except Exception as e: self.retry(exc=e) 

Client flow: SwiftUI and Jetpack Compose

// iOS — request export and poll status class DataExportViewModel: ObservableObject { @Published var exportState: ExportState = .idle func requestExport() async { exportState = .requesting let job = try await api.requestDataExport() exportState = .processing(jobID: job.id) await pollStatus(jobID: job.id) } private func pollStatus(jobID: String) async { while true { try? await Task.sleep(nanoseconds: 30_000_000_000) // 30 seconds let status = try await api.getExportStatus(jobID: jobID) if status.isReady { exportState = .ready(downloadURL: status.downloadURL!) return } } } } 

Once ready is received, prompt the user to save the file via UIDocumentPickerViewController (iOS) or ActivityResultContracts.CreateDocument (Android). Do not save to Documents automatically without consent.

How often can a user request export?

Limit frequency to one request every 24–48 hours. Without limits, users may generate dozens of requests daily, overloading the database. Display the date of the last export and the time until the next possible request.

Why is the asynchronous approach the only reliable solution?

Synchronous export is simple to implement, but for volumes over 5,000 records it blocks the connection and causes timeouts. Asynchronous, on the other hand, scales: we process up to 10 requests per minute without performance loss. Full export for one user takes from 10–15 seconds (synchronous) to 2–3 minutes (asynchronous), but the API responds in 200 ms. For the user, this means a more stable app and a notification when the file is ready.

What our work includes

  • Audit of current architecture and data
  • Design of the export scheme (API, queues, storage)
  • Implementation of server-side API and background tasks
  • Client UI with polling and progress indication
  • Testing with real data (ReplayKit, TestFlight)
  • Documentation and post-launch support

Contact us to evaluate your project—we will estimate cost and timeline without obligation. Order an audit of your current architecture—we will prepare the optimal solution for your stack.