Get your dream built 10x faster

How to integrate Spotify Player with OpenClaw

We build custom applications 5x faster and cheaper 🚀

Book a Free Consultation
4.9
Clutch rating 🌟
600+
Happy partners
17+
Countries served
190+
Team members
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Stuck on an error? Book a 30-minute call with an engineer and get a direct fix + next steps. No pressure, no commitment.

How to integrate Spotify Player with OpenClaw

 

Direct answer

 

High-level: Build a small external service that handles the Spotify OAuth (authorization code) flow, stores user refresh tokens securely, and exposes a simple authenticated REST surface your OpenClaw skill calls. The skill (installed via your OpenClaw/ClawHub workflow) should forward intent parameters (play, pause, play track/URI, seek, get current track) to that service; the service makes the real Spotify Web API calls (PUT /v1/me/player/play, PUT /v1/me/player/pause, GET /v1/me/player/currently-playing) using fresh access tokens. Keep long-lived state and token refresh outside the agent runtime, require Spotify Premium for playback control, request correct scopes, and debug by checking OAuth token exchanges, API responses, and logs.

 

Details — architecture and responsibilities

 

  • Split responsibilities — what runs where:
    • OpenClaw skill/agent: parses user intents, collects parameters (device id, track URI, offsets), and calls your external service's API (simple REST request, authenticated per-user).
    • External service (recommended): handles OAuth redirects and token exchange; stores refresh tokens securely (database or secret store); refreshes access tokens; issues Spotify Web API calls; optionally polls playback state or runs a Web Playback client for push-like events.
    • External infra: database for user tokens, background scheduler/worker for refresh/polling, HTTPS endpoints for OAuth redirect and API calls, logging/observability.
  • Why external service? Agent runtimes are ephemeral and not intended for long-term secrets or scheduled tasks. OAuth refresh logic, persistent tokens, and any polling should live in standard long-running services.

 

Details — Spotify OAuth and scopes

 

  • Use Authorization Code flow (not implicit): user is redirected to Spotify to sign in and approve scopes, you exchange the returned code for an access token and refresh token. Store the refresh token server-side.
  • Required scopes for playback control and state:
    • user-modify-playback-state — start/stop/transfer playback.
    • user-read-playback-state — read current playback state and available devices.
    • user-read-currently-playing — get currently playing track.
    • streaming — only necessary if using the Web Playback SDK in a browser/web client.
  • Note on account type: control of playback via the Web API generally requires the user to have Spotify Premium; enforce this in UX and error handling.

 

Concrete OAuth steps and example requests

 

  • 1) Build the authorization URL — redirect user to Spotify to approve scopes:
    https://accounts.spotify.com/authorize?client_id=YOUR_CLIENT_ID&response_type=code&redirect_uri=YOUR_REDIRECT_URI&scope=user-modify-playback-state%20user-read-playback-state%20user-read-currently-playing&state=RANDOM_STATE
      
  • 2) Exchange code for tokens — POST to Spotify token endpoint:
    POST https://accounts.spotify.com/api/token
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic BASE64(client_id:client_secret)
    
    grant_type=authorization_code&code=CODE_FROM_QUERY&redirect_uri=YOUR_REDIRECT\_URI
      

    Response will include access_token, token_type, expires_in, refresh_token (store this).

  • 3) Refresh token — when the access token expires, exchange refresh token:
    POST https://accounts.spotify.com/api/token
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic BASE64(client_id:client_secret)
    
    grant_type=refresh_token&refresh_token=USER_REFRESH\_TOKEN
      

 

Example Spotify API calls (use these from your external service)

 

  • Start/play a track or context — PUT /v1/me/player/play:
    PUT https://api.spotify.com/v1/me/player/play?device_id=DEVICE_ID
    Authorization: Bearer ACCESS\_TOKEN
    Content-Type: application/json
    
    {
      "uris": ["spotify:track:TRACK\_ID"],
      "position\_ms": 0
    }
      
  • Pause playback — PUT /v1/me/player/pause:
    PUT https://api.spotify.com/v1/me/player/pause?device_id=DEVICE_ID
    Authorization: Bearer ACCESS\_TOKEN
      
  • Get currently playing — GET /v1/me/player/currently-playing:
    GET https://api.spotify.com/v1/me/player/currently-playing
    Authorization: Bearer ACCESS\_TOKEN
      

 

Working code examples

 

  • Exchange code for tokens (curl):
    // Exchange authorization code for tokens
    curl -X POST https://accounts.spotify.com/api/token \\
      -H "Authorization: Basic BASE64(client_id:client_secret)" \\
      -H "Content-Type: application/x-www-form-urlencoded" \\
      -d "grant_type=authorization_code&code=AUTH_CODE&redirect_uri=YOUR_REDIRECT_URI"
      
  • Call Spotify play endpoint (Node/Fetch):
    // Start playback on a user's device
    const fetch = require('node-fetch');
    
    async function playTrack(accessToken, deviceId, trackUri) {
      const url = 'https://api.spotify.com/v1/me/player/play' + (deviceId ? `?device_id=${encodeURIComponent(deviceId)}` : '');
      const body = JSON.stringify({ uris: [trackUri] });
    
      const res = await fetch(url, {
        method: 'PUT',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json',
        },
        body,
      });
    
      if (!res.ok) {
        const text = await res.text();
        throw new Error(`Spotify play failed: ${res.status} ${text}`);
      }
    }
      

 

How the OpenClaw skill should call your service

 

  • Skill to service protocol:
    • Skill authenticates to your service as the agent caller (short-lived key or signed request). Do not embed user refresh tokens in the skill.
    • Skill sends a request like POST /v1/spotify/play with body { user_id, device_id, track_uri } and your service maps user_id to stored refresh token and calls Spotify.
  • Keep user consent explicit: when a new user wants Spotify control, have them open your OAuth link (in a browser) to connect their account; this is an out-of-band step the skill can instruct the user to perform.

 

Persistence, scaling, and runtime concerns

 

  • Persist tokens securely: use a database + encryption or a secret manager. Do not store refresh tokens in ephemeral agent environment variables.
  • Token refresh: centralize refresh logic in one place. If many agents call your service concurrently, ensure token refresh is serialized or safely retried to avoid race conditions.
  • Polling vs push: Spotify Web API does not provide reliable server-side push for playback state. If you need state updates, implement periodic polling or a browser-based Web Playback SDK that reports events to your service.
  • Rate limits: handle 429 responses and retry after the Retry-After header.

 

Security and validation

 

  • Validate redirect URIs registered in the Spotify Developer Dashboard.
  • Use PKCE if you ever support clients that can’t keep a client_secret (public clients); otherwise Authorization Code with client_secret is standard for server-side apps.
  • Least privilege scopes: request only the scopes you need. Make scope expiration and refresh visible to users in your UI.

 

Debugging checklist

 

  • Confirm user completed OAuth and you have a refresh\_token stored.
  • Inspect token exchange response for errors and correct Authorization header (Basic base64(client_id:client_secret)).
  • Check access token expiration and ensure refresh flow works (POST to /api/token with grant_type=refresh_token).
  • Call GET /v1/me/player to verify devices and current state before issuing play commands.
  • Handle 401 (invalid token) by refreshing; handle 403/403s for missing scope or no Premium account and surface message to user.
  • Log request/response bodies and Spotify headers (timestamps, request id) for troubleshooting rate-limit issues.

Book Your Free 30‑Minute Migration Call

Speak one‑on‑one with a senior engineer about your no‑code app, migration goals, and budget. In just half an hour you’ll leave with clear, actionable next steps—no strings attached.

Book a Free Consultation

Troubleshooting Spotify Player and OpenClaw Integration

1

AuthAdapter - OAuth & refresh

 

Direct answer

 

Implement an AuthAdapter that stores refresh tokens outside the agent (DB or secrets store), reads client_id/secret from environment variables, exchanges refresh tokens at the provider token endpoint, updates stored tokens, and returns a valid access_token to skills before each call.

 

Pattern + example

 

Keep tokens stateful outside the runtime, refresh proactively, and fail-safe if refresh fails.

  • Example (Node.js)
```javascript // Simple AuthAdapter const axios = require('axios'); async function getAccessToken(userId, db) { // db.get returns {access_token, refresh_token, expires_at} const tok = await db.get(userId); if (tok && Date.now() < tok.expires_at - 60000) return tok.access_token; // refresh const res = await axios.post(process.env.TOKEN_URL, new URLSearchParams({ grant_type: 'refresh_token', refresh_token: tok.refresh_token, client_id: process.env.CLIENT_ID, client_secret: process.env.CLIENT_SECRET }).toString(), {headers:{'Content-Type':'application/x-www-form-urlencoded'}}); // update store await db.update(userId, {access_token: res.data.access_token, refresh_token: res.data.refresh_token||tok.refresh_token, expires_at: Date.now()+res.data.expires_in*1000}); return res.data.access_token; } ```

2

PlaybackAdapter - Connect devices & ClawEndpoint

Use a PlaybackAdapter to translate Claw skill commands into concrete device API calls, and expose a secure ClawEndpoint webhook that authenticates requests, validates webhooks, routes commands to the adapter, and returns execution status. Keep credentials in env vars, persist device state outside the agent runtime, and rely on logs + API response inspection for debugging.

 

Implementation sketch

 

Key steps:

  • Authenticate via env tokens/OAuth and validate incoming signatures.
  • Map skill intent → device API call in the adapter.
  • Persist state in Redis/DB; use retries and idempotency.
// PlaybackAdapter maps high-level commands to device REST calls
class PlaybackAdapter {
  constructor(token){ this.token = token }
  async play(deviceId, url){
    // call device API
    return fetch(`https://api.device/${deviceId}/play`, { method:'POST', headers:{ Authorization:`Bearer ${this.token}` }, body: JSON.stringify({ url }) })
  }
}
// ClawEndpoint: express webhook verifies signature then routes to adapter

3

AudioSink - stuttering/buffer tuning

 

Direct answer

 

Fix stuttering by increasing the audio sink's buffer/jitter buffer, pre-buffering more frames, matching sample rates, and moving tight audio processing out of the agent runtime to a dedicated worker or external service; use environment variables to tune buffer sizes and enable verbose audio logs to measure underruns.

 

Details and steps

 

Start by collecting logs and CPU/GC metrics from the OpenClaw agent runtime.

  • Increase buffer (frames/ms) and prefill before playback.
  • Match sample rates end-to-end and resample upstream if needed.
  • Measure network jitter and add a jitter buffer; move decoding to a separate process if CPU-bound.
  • Expose settings via env vars (e.g., AUDIO_BUFFER_MS, PREFILL_MS, LOG_LEVEL) and iterate while watching underrun counters.

4

EventBus - mapping events to ClawPlaybackState

Direct answer: Map EventBus event types (play, pause, stop, seek, buffer-start, buffer-end, error) to the nearest ClawPlaybackState (PLAYING, PAUSED, STOPPED, SEEKING, BUFFERING, ERROR). Treat events as authoritative only after validation, apply idempotency and ordering, and publish resulting ClawPlaybackState back on the EventBus.

 

Mapping pattern

 
  • play → PLAYING
  • pause → PAUSED
  • stop → STOPPED
  • seek → SEEKING then PLAYING or PAUSED
  • buffer-start → BUFFERING
  • buffer-end → previous play/pause state
  • error → ERROR

 

Implementation notes

 
  • Validate events (IDs, timestamps, auth) before state change.
  • Apply ordering and dedupe to avoid regressions.
  • Emit state changes back to EventBus and store minimal external state when needed.
Book a Free Consultation

Still stuck?
Copy this prompt into ChatGPT and get a clear, personalized explanation.

This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.

AI AI Prompt


Recognized by the best

Trusted by 600+ businesses globally

From startups to enterprises and everything in between, see for yourself our incredible impact.

RapidDev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with.

They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

Arkady
CPO, Praction
Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost.

He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Donald Muir
Co-Founder, Arc
RapidDev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space.

They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Mat Westergreen-Thorne
Co-CEO, Grantify
RapidDev is an excellent developer for custom-code solutions.

We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Emmanuel Brown
Co-Founder, Church Real Estate Marketplace
Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 

This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Samantha Fekete
Production Manager, Media Production Company
The pSEO strategy executed by RapidDev is clearly driving meaningful results.

Working with RapidDev has delivered measurable, year-over-year growth. Comparing the same period, clicks increased by 129%, impressions grew by 196%, and average position improved by 14.6%. Most importantly, qualified contact form submissions rose 350%, excluding spam.

Appreciation as well to Matt Graham for championing the collaboration!

Michael W. Hammond
Principal Owner, OCD Tech

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â