2026-05-31·5 min read·sota.io Team

EU Data Act Art.27 Switching Obstacle Compliance 2026: Removing Lock-In Patterns, Service Degradation & Contractual Restrictions

Post #1418 in the sota.io EU Cloud Compliance Series

EU Data Act Art.27 Switching Obstacle Compliance and Lock-In Pattern Removal 2026

The EU Data Act (Regulation (EU) 2023/2854) does not merely grant customers the right to switch cloud providers — it actively prohibits providers from making switching difficult. Article 27 targets the commercial and technical obstacles that cloud providers have historically used to retain customers against their will: service degradation during the switching window, removal of integrations, retroactive data deletion, and contractual terms that restrict what customers can export.

This is the third post in our EU-DATA-ACT-CLOUD-SWITCHING-2026 series. The first post covered the switching request API and 30-day state machine. The second post covered data format standards and interoperability requirements. This post covers what you are prohibited from doing once a customer initiates a switch — and how to audit your platform for lock-in patterns before enforcement arrives.


What Art.27 Actually Prohibits

Article 27 of the EU Data Act creates an affirmative obligation: providers of data processing services must not create or maintain commercial or technical obstacles that prevent customers from switching or make switching disproportionately burdensome. The provision targets three categories of obstacle:

Category 1: Commercial Obstacles

Commercial obstacles are contractual or pricing mechanisms that increase the effective cost of switching beyond the data export itself. Prohibited examples include:

Early termination penalties tied to switching — A customer who initiates a switch under Art.23 retains the right to switch regardless of contractual lock-in periods. Termination fees that apply specifically when a customer exercises their switching right are prohibited. (Termination fees for ending a subscription early for other reasons remain lawful — the prohibition is narrow.)

Data retrieval fees during the switching window — The fee phase-down schedule (free switching from January 2027) applies to the switching service itself. Charging additional fees for data access, API calls, or export processing during the switching window is a prohibited obstacle if those fees are not disclosed in pre-contractual information.

Bundled service withdrawal — Withdrawing other services, integrations, or support levels that the customer is entitled to during the 30-day switching window as leverage to prevent switching is an obstacle. If a customer is paying for a Professional plan, they must receive Professional plan service quality throughout the 30-day export window.

Retrospective scope limitation — Contractual terms that limit what data a customer can export post-initiation (e.g., "export right applies only to data created in the last 12 months") are prohibited if those terms were not clearly disclosed pre-contract and if they materially reduce the switching utility.

Category 2: Technical Obstacles

Technical obstacles are platform behaviours that degrade the switching experience or make it harder for customers to migrate to a competitor:

API throttling during export — Reducing rate limits on the switching API or data export endpoints below normal operational limits once a switching request is initiated is an obstacle. Your export pipeline must operate at the same performance level as your production API.

Dependency removal — Removing webhooks, third-party integrations, or OAuth connections that the customer relies on as part of their export workflow during the switching window is prohibited. Customers need their integrations to function in order to validate that exported data is complete.

Format degradation — Providing a reduced-fidelity export (e.g., CSV instead of the promised JSON with full schema) after a switching request is initiated is a technical obstacle. The format requirements in Chapter IV apply throughout the switching process.

Deletion before completion — Initiating data deletion before the switching window closes — or before the customer explicitly confirms that their export is complete — is prohibited. The 30-day window must remain available in full.

Category 3: Contractual Restrictions

Contractual terms that discourage or prevent customers from switching are void under the Data Act where they conflict with Art.27:

Any clause that conditions the switching right on provider consent, imposes post-switching use restrictions on the customer's own data, or excludes switching from your service commitments is void to the extent it conflicts with the Data Act.


Auditing Your Platform for Lock-In Patterns

Before your first switching request arrives — or before a regulator's audit — run this audit framework across your platform.

Step 1: Map Your Switching-Adjacent Rate Limits

Pull your current rate limit configuration for every endpoint that a switching customer would use:

// Audit: switching-adjacent endpoint rate limits
interface EndpointRateLimit {
  path: string
  normalLimitPerHour: number
  switchingWindowLimitPerHour: number
  differencePercent: number
}

async function auditSwitchingRateLimits(): Promise<EndpointRateLimit[]> {
  const switchingEndpoints = [
    '/api/v1/switching/export',
    '/api/v1/switching/status',
    '/api/v1/data/export',
    '/api/v1/webhooks',
    '/api/v1/integrations',
  ]
  
  const results: EndpointRateLimit[] = []
  
  for (const path of switchingEndpoints) {
    const normalLimit = await getRateLimitConfig(path, { switchingWindow: false })
    const switchingLimit = await getRateLimitConfig(path, { switchingWindow: true })
    
    results.push({
      path,
      normalLimitPerHour: normalLimit.requestsPerHour,
      switchingWindowLimitPerHour: switchingLimit.requestsPerHour,
      differencePercent: ((switchingLimit.requestsPerHour - normalLimit.requestsPerHour) / normalLimit.requestsPerHour) * 100,
    })
  }
  
  // Flag any endpoint where switching window limit is lower than normal
  return results.filter(r => r.differencePercent < 0)
}

If this function returns any results, you have a throttling obstacle. Fix: enforce switching window rate limits at parity or above normal operational limits.

Step 2: Audit Termination Triggers

Check whether your subscription termination logic can fire during a switching window:

// Anti-pattern: termination logic that doesn't respect switching window
class SubscriptionService {
  async terminateSubscription(tenantId: string, reason: string): Promise<void> {
    // BAD: this could fire during an active switching window
    await this.db.tenant.update({ where: { id: tenantId }, data: { status: 'terminated' } })
    await this.scheduleDataDeletion(tenantId, delayDays: 30)
  }
}

// Compliant: switching window gate
class SubscriptionService {
  async terminateSubscription(tenantId: string, reason: string): Promise<void> {
    const activeSwitching = await this.switchingRepo.findActive(tenantId)
    
    if (activeSwitching && reason !== 'customer_completed_switching') {
      // Defer termination — log for audit
      await this.switchingRepo.recordDeferredTermination(tenantId, reason)
      return
    }
    
    await this.db.tenant.update({ where: { id: tenantId }, data: { status: 'terminated' } })
    await this.scheduleDataDeletion(tenantId, delayDays: 30)
  }
}

Step 3: Review Your Terms of Service for Void Clauses

Run a plain-text search across your ToS, DPA, and MSA for these patterns:

# Patterns indicating potentially void switching restrictions
grep -i -E \
  "switching.*approval|prior.*consent.*export|export.*competitor|limit.*portability|switching.*not.*covered|export.*right.*reserved|data.*deletion.*30.*days" \
  ./legal/terms-of-service.md \
  ./legal/data-processing-agreement.md \
  ./legal/master-subscription-agreement.md

Each match requires legal review against Art.27. Clauses that condition switching on your approval, restrict use of exported data with competitors, or exclude switching from SLA coverage are the highest risk.

Step 4: Verify Integration Availability During Switching

Test that all integrations remain functional when switching_status = 'in_progress' is set on a tenant:

// Integration test: switching window does not degrade integration availability
describe('switching window integration stability', () => {
  let tenantId: string
  
  beforeAll(async () => {
    tenantId = await createTestTenant()
    await initiateSwitchingRequest(tenantId)
    // tenant.switching_status is now 'in_progress'
  })
  
  test('webhook delivery is unaffected during switching window', async () => {
    const webhook = await createWebhook(tenantId, { url: 'https://test.example.com/hook' })
    await triggerWebhookEvent(tenantId, 'data.exported')
    
    const deliveries = await getWebhookDeliveries(webhook.id, { last: 1 })
    expect(deliveries[0].status).toBe('delivered')
    expect(deliveries[0].responseCode).toBe(200)
  })
  
  test('third-party OAuth connections remain active during switching window', async () => {
    const connections = await getOAuthConnections(tenantId)
    for (const conn of connections) {
      const tokenValid = await validateOAuthToken(conn.id)
      expect(tokenValid).toBe(true)
    }
  })
  
  test('API rate limits are not reduced during switching window', async () => {
    const normalLimits = await getRateLimits(tenantId, { switching: false })
    const switchingLimits = await getRateLimits(tenantId, { switching: true })
    
    for (const [endpoint, limit] of Object.entries(normalLimits)) {
      expect(switchingLimits[endpoint]).toBeGreaterThanOrEqual(limit)
    }
  })
})

Building an Obstacle-Free Switching Window State Machine

The switching window is a 30-day period during which your platform must maintain full service quality. Here is a state machine that enforces this while preventing the common lock-in anti-patterns:

import { z } from 'zod'

const SwitchingState = z.enum([
  'requested',     // Customer submitted switching request
  'validated',     // Switching request validated, export started
  'exporting',     // Data export in progress
  'export_ready',  // Export complete, available for download
  'completed',     // Customer confirmed receipt
  'expired',       // 30-day window passed without completion (edge case)
])

type SwitchingState = z.infer<typeof SwitchingState>

interface SwitchingTransition {
  from: SwitchingState
  to: SwitchingState
  allowedActions: string[]
  prohibitedPlatformActions: string[]
}

const SWITCHING_POLICY: SwitchingTransition[] = [
  {
    from: 'requested',
    to: 'validated',
    allowedActions: ['verify_identity', 'acknowledge_request'],
    prohibitedPlatformActions: [
      'reduce_rate_limits',
      'remove_integrations',
      'initiate_data_deletion',
      'suspend_support',
      'apply_early_termination_fee',
    ],
  },
  {
    from: 'validated',
    to: 'exporting',
    allowedActions: ['start_export_job', 'notify_customer'],
    prohibitedPlatformActions: [
      'reduce_rate_limits',
      'change_export_format',
      'remove_integrations',
      'initiate_data_deletion',
    ],
  },
  {
    from: 'exporting',
    to: 'export_ready',
    allowedActions: ['generate_download_link', 'notify_customer'],
    prohibitedPlatformActions: [
      'delete_export_before_customer_confirms',
      'modify_export_scope',
    ],
  },
  {
    from: 'export_ready',
    to: 'completed',
    allowedActions: ['confirm_download', 'close_switching_request'],
    prohibitedPlatformActions: [
      'delete_data_before_customer_confirms',
    ],
  },
]

class SwitchingWindowEnforcer {
  async assertActionAllowed(
    tenantId: string,
    action: string,
  ): Promise<void> {
    const switching = await this.repo.findActive(tenantId)
    if (!switching) return // No active switching window
    
    const policy = SWITCHING_POLICY.find(p => p.from === switching.state)
    if (!policy) return
    
    if (policy.prohibitedPlatformActions.includes(action)) {
      // Log for compliance audit trail
      await this.auditLog.record({
        tenantId,
        action,
        blocked: true,
        reason: 'EU Data Act Art.27 switching window protection',
        switchingWindowId: switching.id,
        timestamp: new Date().toISOString(),
      })
      
      throw new SwitchingWindowViolationError(
        `Action '${action}' is prohibited during active switching window (Art.27 EU Data Act)`,
      )
    }
  }
}

// Usage: inject into any service that might violate the switching window
class DataDeletionService {
  constructor(
    private readonly enforcer: SwitchingWindowEnforcer,
  ) {}
  
  async scheduleDataDeletion(tenantId: string): Promise<void> {
    await this.enforcer.assertActionAllowed(tenantId, 'initiate_data_deletion')
    // Safe to proceed — no active switching window, or deletion is permitted
    await this.deleteData(tenantId)
  }
}

What Constitutes a "Disproportionate Burden"?

The regulation does not define "disproportionate" with numerical precision. The European Commission's guidance indicates that the proportionality assessment weighs:

Against the provider:

In the provider's favour:

In practice, the safest position is to treat the switching window as a protected period where your platform operates exactly as it does for a non-switching customer — same rate limits, same integrations, same support SLA, same data access. Anything less requires documented justification.


Enforcement Exposure

The EU Data Act enforcement framework assigns supervisory responsibility to national competent authorities (NCAs) in each Member State. Penalties are set at the national level but the regulation requires that they be "effective, proportionate, and dissuasive."

Several NCAs have already signalled their priority areas for 2026 enforcement:

The practical enforcement risk for SaaS providers is not primarily financial penalty — it is injunctive relief. An NCA can require you to maintain data availability beyond the 30-day window if a customer complaint shows that switching was obstructed. This creates an open-ended data retention obligation that is operationally much more costly than compliance from the start.


Pre-Contractual Disclosure Checklist

Art.27 compliance begins before the customer signs — you must disclose switching conditions in your contracts and pricing pages. Run this pre-contractual checklist:

## EU Data Act Art.27 Pre-Contractual Disclosure Checklist

### In Terms of Service / MSA
- [ ] Switching right explicitly stated (reference to Regulation (EU) 2023/2854)
- [ ] 30-day export window duration disclosed
- [ ] Data formats available for export listed
- [ ] Fee schedule for switching assistance disclosed (current year)
- [ ] No clause conditioning switching on provider approval
- [ ] No clause restricting post-switch use of customer's own data
- [ ] Support SLA coverage during switching window confirmed

### In Pricing Page / Plan Comparison
- [ ] Switching/export fee disclosed per tier
- [ ] Data retention after termination disclosed
- [ ] Export format per tier disclosed (if format varies by plan)

### In Data Processing Agreement (DPA)
- [ ] Data deletion timeline after completed switch disclosed
- [ ] Backup retention during switching window disclosed
- [ ] Sub-processor obligations during switching window addressed

What This Means for Smaller SaaS Platforms

If your monthly active users are below 10,000 and your annual turnover is below €10 million, you benefit from the SME provisions of the Data Act — reduced obligations, lighter administrative burden, and transitional periods for some technical requirements. The Art.27 prohibition on obstacles, however, applies to all providers regardless of size. The prohibition is a floor, not a graduated obligation.

For a smaller SaaS team, the practical priority is:

  1. Remove void ToS clauses — this is a legal document edit, not engineering work
  2. Implement the switching window gate — the SwitchingWindowEnforcer pattern above integrates into your existing subscription service
  3. Parity rate limits — verify export endpoints are not throttled differently than production

The switching request API and 30-day state machine from Post #1 gives you the foundation. The obstacle-removal work in this post is a layer on top of that foundation.


Next in the Series

The fourth post covers EU Data Act compliance for receiving providers — the technical obligations on the cloud provider that the customer is switching to. Receiving providers have their own set of obligations under Chapter IV: accepting ported data in standard formats, validating import completeness, and maintaining migration SLAs. We will include a TypeScript reference implementation for an import pipeline that satisfies the interoperability requirements.


This post is part of the sota.io EU Cloud Compliance Series covering Regulation (EU) 2023/2854. For more EU compliance guides, visit sota.io/blog.

EU-Native Hosting

Ready to move to EU-sovereign infrastructure?

sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.