How to Scrape TikTok User Data with PowerShell on Windows

Published on May 29, 2026

PowerShell is the most underrated tool in the TikTok scraping conversation. While Python and Node tutorials dominate, every Windows server already ships with PowerShell, every sysadmin already knows it, and Invoke-RestMethod deserializes JSON into objects you can pipe directly into Export-Csv, Export-Excel, or SQL Server. No virtual environments. No pip install. No Node version drama. Just a script, a scheduled task, and reliable data flowing into your warehouse every morning.

This tutorial shows how to pull TikTok user profiles, follower counts, video lists, and follower graphs using PowerShell 7 and the TikLiveAPI REST API. We will cover authentication via Windows Credential Manager, idiomatic PSCustomObject handling, pagination, parallel fetches with ForEach-Object -Parallel, retry logic, CSV export, and a production-ready Task Scheduler deployment.

Why PowerShell for TikTok scraping

PowerShell is built for exactly this kind of work: hit a JSON HTTP endpoint, transform the response, and write it somewhere useful. Three reasons it beats spinning up a Python project on a Windows box:

  • Native everywhere. Windows Server 2016 and later ship with Windows PowerShell 5.1. PowerShell 7 is a quick MSI install and runs cross-platform.
  • JSON is first-class. Invoke-RestMethod auto-converts responses to PSCustomObject. You access $response.stats.followerCount directly - no manual deserialization.
  • Task Scheduler integration. Daily TikTok pulls become a one-line scheduled task with built-in logging, retries, and email alerts.

Prerequisites

  • PowerShell 7.4+ recommended (for ForEach-Object -Parallel and HTTP/2). Stock Windows PowerShell 5.1 also works but lacks parallel cmdlets.
  • A TikLiveAPI account and API key. Sign up at register, then copy your key from profile. Pricing starts pay-as-you-go on the pricing page - 1 request = 1 credit, credits never expire.
  • Windows 10/11 or Windows Server 2019+.

Storing the API key securely

Never hard-code the API key in a script. PowerShell has two clean options on Windows: the SecretManagement module backed by Windows Credential Manager, or DPAPI-encrypted files via ConvertFrom-SecureString.

The Credential Manager approach is best for interactive servers:

Install-Module Microsoft.PowerShell.SecretManagement -Scope CurrentUser
Install-Module Microsoft.PowerShell.SecretStore -Scope CurrentUser
Register-SecretVault -Name TikLive -ModuleName Microsoft.PowerShell.SecretStore -DefaultVault
Set-Secret -Name TikLiveApiKey -Secret 'YOUR_API_KEY_HERE'

For headless service accounts, DPAPI is simpler. It encrypts the key against the current user SID so only that account can read it:

Read-Host 'Paste API key' -AsSecureString |
    ConvertFrom-SecureString |
    Set-Content -Path "$env:USERPROFILE\.tiklive.key"

Then in your script:

$secure = Get-Content "$env:USERPROFILE\.tiklive.key" | ConvertTo-SecureString
$ApiKey = [System.Net.NetworkCredential]::new('', $secure).Password

Your first request: Invoke-RestMethod with X-Api-Key

TikLiveAPI authenticates with a single HTTP header: X-Api-Key. Every request goes to https://api.tikliveapi.com. Let's fetch a profile:

$BaseUrl = 'https://api.tikliveapi.com'
$Headers = @{ 'X-Api-Key' = $ApiKey }

$response = Invoke-RestMethod -Uri "$BaseUrl/userinfo-by-username/?username=charlidamelio" `
    -Headers $Headers -Method Get

$response.user.nickname
$response.stats.followerCount
$response.stats.heartCount
$response.stats.videoCount

That's it. The response is a PSCustomObject with two top-level properties: user (nested object with id, uniqueId, nickname, avatarThumb, avatarMedium, avatarLarger, signature, verified, secUid, privateAccount, bioLink) and stats (camelCase counters: followingCount, followerCount, heartCount, videoCount, diggCount). See the full schema in the Users documentation.

Resolving usernames to numeric IDs

Many endpoints take a numeric userid rather than a username. Use /userid/ to convert:

function Get-TikTokUserId {
    param([string]$Username)
    $result = Invoke-RestMethod -Uri "$BaseUrl/userid/?username=$Username" -Headers $Headers
    return $result.id
}

$userId = Get-TikTokUserId -Username 'charlidamelio'
Write-Host "Numeric ID: $userId"

The response is a flat object with a single string field id. Cache these locally - they never change for a given account.

Pagination: cursor vs time

TikLiveAPI uses two pagination styles. /user-posts/ uses a cursor (millisecond timestamp string) plus a hasMore boolean. Follower and following endpoints use a time field (unix seconds) instead.

Here is a clean PowerShell loop that handles cursor-based pagination for video lists:

function Get-TikTokUserPosts {
    param(
        [string]$UserId,
        [int]$MaxVideos = 200
    )

    $allVideos = [System.Collections.Generic.List[object]]::new()
    $cursor = '0'

    do {
        $url = "$BaseUrl/user-posts/?userid=$UserId&count=35&cursor=$cursor"
        $page = Invoke-RestMethod -Uri $url -Headers $Headers

        foreach ($video in $page.videos) {
            $allVideos.Add($video)
        }

        $cursor = $page.cursor
        $hasMore = $page.hasMore
    } while ($hasMore -and $allVideos.Count -lt $MaxVideos)

    return $allVideos
}

Each video in videos[] uses snake_case fields: aweme_id, video_id, title, play, wmplay, play_count, digg_count, comment_count, share_count, create_time, and a nested author object.

For followers, pagination uses time instead of cursor, and the top-level key is followers:

function Get-TikTokFollowers {
    param([string]$UserId, [int]$MaxFollowers = 1000)

    $all = [System.Collections.Generic.List[object]]::new()
    $time = 0

    do {
        $url = "$BaseUrl/user-followers/?userid=$UserId&count=50&time=$time"
        $page = Invoke-RestMethod -Uri $url -Headers $Headers
        $page.followers | ForEach-Object { $all.Add($_) }
        $time = $page.time
    } while ($page.hasMore -and $all.Count -lt $MaxFollowers)

    return $all
}

Note: the /user-following/ endpoint uses the plural key followings (not following) - a common gotcha worth pinning to your monitor.

Production retry with exponential backoff

Networks fail. TikTok occasionally returns 5xx during regional CDN hiccups. Wrap calls in a retry helper:

function Invoke-WithRetry {
    param(
        [scriptblock]$ScriptBlock,
        [int]$MaxAttempts = 4,
        [int]$BaseDelaySeconds = 2
    )

    for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {
        try {
            return & $ScriptBlock
        } catch {
            $status = $_.Exception.Response.StatusCode.value__
            if ($attempt -eq $MaxAttempts -or ($status -ge 400 -and $status -lt 500 -and $status -ne 429)) {
                throw
            }
            $delay = [Math]::Pow(2, $attempt - 1) * $BaseDelaySeconds
            Write-Warning "Attempt $attempt failed (HTTP $status). Retrying in ${delay}s."
            Start-Sleep -Seconds $delay
        }
    }
}

$profile = Invoke-WithRetry { Invoke-RestMethod -Uri "$BaseUrl/userinfo-by-username/?username=mrbeast" -Headers $Headers }

This retries transient 5xx and 429 (rate limit) responses with exponential backoff, but fails fast on 4xx like 401 (bad key) or 404. The default rate limit is 200 requests per minute - more than enough for most batch jobs.

Concurrency: parallel fetches

PowerShell 7 ships ForEach-Object -Parallel, which is perfect for fanning out across hundreds of usernames. Each iteration runs in its own runspace, so you must pass shared variables via $using::

$usernames = Get-Content .\target-creators.txt
$apiKey = $ApiKey
$baseUrl = $BaseUrl

$results = $usernames | ForEach-Object -Parallel {
    $headers = @{ 'X-Api-Key' = $using:apiKey }
    try {
        $r = Invoke-RestMethod -Uri "$using:baseUrl/userinfo-by-username/?username=$_" -Headers $headers
        [PSCustomObject]@{
            Username      = $r.user.uniqueId
            Nickname      = $r.user.nickname
            Followers     = $r.stats.followerCount
            Hearts        = $r.stats.heartCount
            Videos        = $r.stats.videoCount
            Verified      = $r.user.verified
            FetchedAt     = (Get-Date).ToString('s')
        }
    } catch {
        Write-Warning "Failed: $_"
    }
} -ThrottleLimit 8

$results | Export-Csv -Path .\tiktok-creators.csv -NoTypeInformation -Encoding UTF8

On PowerShell 5.1, fall back to Start-ThreadJob from the ThreadJob module. Keep ThrottleLimit at or below 8 to stay under the 200 req/min limit while leaving headroom for retries.

Exporting to CSV, Excel, and SQL

Once data is a PSCustomObject array, output is trivial:

$results | Export-Csv -Path .\creators.csv -NoTypeInformation -Encoding UTF8

# Excel (requires ImportExcel module)
$results | Export-Excel -Path .\creators.xlsx -AutoSize -TableName Creators

# SQL Server (requires SqlServer module)
$results | Write-SqlTableData -ServerInstance 'sql01' -DatabaseName 'Analytics' -TableName 'tiktok_creators' -Force

Scheduling: Task Scheduler XML

To run your scraper every morning at 06:00, save the script as C:\Scripts\TikTokDaily.ps1 and register a task:

$action = New-ScheduledTaskAction -Execute 'pwsh.exe' `
    -Argument '-NoProfile -File C:\Scripts\TikTokDaily.ps1'

$trigger = New-ScheduledTaskTrigger -Daily -At 06:00

$principal = New-ScheduledTaskPrincipal -UserId 'NT AUTHORITY\SYSTEM' `
    -LogonType ServiceAccount -RunLevel Highest

$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable `
    -ExecutionTimeLimit (New-TimeSpan -Hours 2) `
    -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 5)

Register-ScheduledTask -TaskName 'TikLiveAPI Daily Pull' `
    -Action $action -Trigger $trigger -Principal $principal -Settings $settings

The task runs as SYSTEM, restarts on failure, and times out after two hours.

Logging with Write-EventLog

For production jobs, log to the Windows Event Log so Splunk or Azure Monitor can pick it up:

New-EventLog -LogName Application -Source 'TikLiveAPI' -ErrorAction SilentlyContinue

try {
    $count = (Get-TikTokFollowers -UserId $userId -MaxFollowers 5000).Count
    Write-EventLog -LogName Application -Source 'TikLiveAPI' `
        -EntryType Information -EventId 1000 `
        -Message "Pulled $count followers for $userId"
} catch {
    Write-EventLog -LogName Application -Source 'TikLiveAPI' `
        -EntryType Error -EventId 9000 -Message $_.Exception.Message
    throw
}

Other useful endpoints

The full documentation lists 37 endpoints. A few common picks for sysadmin pipelines:

  • /post-detail/ - flat snake_case object with aweme_id, play, wmplay, hdplay (HD no-watermark download URLs), plus full counter set.
  • /post-comments/ - returns comments[] with each item carrying id (not cid), text, digg_count, reply_total, paginated by cursor + hasMore.
  • /search-video/ - keyword video search with publish_time and sort_by filters.
  • /download-video/ - direct watermark-free download URL given a TikTok video URL.

Test any endpoint live in the browser-based playground before wiring it into PowerShell.

FAQ

Does this work on PowerShell 5.1?

Yes. Invoke-RestMethod, retry, and CSV export are identical. You lose ForEach-Object -Parallel - use Start-ThreadJob from the ThreadJob module instead.

How do I handle 429 rate limit errors?

The standard limit is 200 requests per minute. The Invoke-WithRetry helper above already retries 429 with exponential backoff. For higher limits, contact support.

Can I run this on Linux or macOS?

Yes. PowerShell 7 is cross-platform. Swap Register-ScheduledTask for a cron entry and replace SecretStore with libsecret or environment variables.

What if a username has special characters?

Wrap query parameter values in [uri]::EscapeDataString($value) to handle dots, hyphens, and non-ASCII characters safely.

Does the dashboard charge credits for failed requests?

No. Credit deduction happens on the external API server only when a request returns successfully. Failed lookups (404, 5xx) do not consume credits.

Ready to deploy? Grab your key from profile, browse more patterns on the blog, and check the Users endpoint reference for the full PSCustomObject shapes you will be working with.

Build with the TikTok API

Ready to put what you read into code? Try our endpoints live or grab the full reference.

Open Playground Read Documentation