<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sebastian Balog</title>
    <description>The latest articles on DEV Community by Sebastian Balog (@sebastian_balog_c88dc2913).</description>
    <link>https://dev.to/sebastian_balog_c88dc2913</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4144671%2Fa6b94a64-45bd-4305-b1d1-46483e984c60.png</url>
      <title>DEV Community: Sebastian Balog</title>
      <link>https://dev.to/sebastian_balog_c88dc2913</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebastian_balog_c88dc2913"/>
    <language>en</language>
    <item>
      <title>How to run multiple Claude accounts at once (Desktop + Claude Code), and why the obvious hacks break</title>
      <dc:creator>Sebastian Balog</dc:creator>
      <pubDate>Mon, 12 Oct 2026 23:52:50 +0000</pubDate>
      <link>https://dev.to/sebastian_balog_c88dc2913/how-to-run-multiple-claude-accounts-at-once-desktop-claude-code-and-why-the-obvious-hacks-break-19jb</link>
      <guid>https://dev.to/sebastian_balog_c88dc2913/how-to-run-multiple-claude-accounts-at-once-desktop-claude-code-and-why-the-obvious-hacks-break-19jb</guid>
      <description>&lt;p&gt;&lt;em&gt;Disclosure up front: I build &lt;a href="https://doubleclaude.com" rel="noopener noreferrer"&gt;Claude Sessions Pro&lt;/a&gt;, a paid Mac app that does this. Most of this post is the free way to do it yourself, plus what I learned about why the DIY versions misbehave. The app gets one short section near the end.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you have a company Claude account and a personal one, or one account per client, you've hit this: Claude Desktop is signed in to &lt;strong&gt;one&lt;/strong&gt; account. To check the other one, you sign out, sign in, lose your place, and do it again an hour later.&lt;/p&gt;

&lt;p&gt;Claude Code in the terminal has the same problem, just with a different config folder.&lt;/p&gt;

&lt;p&gt;Here's how to fix it, from "free, two lines of shell" to "one click", and the gotchas nobody mentions until you've already set it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Do this&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Two Claude Code (CLI) accounts&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;CLAUDE_CONFIG_DIR=~/.claude-work claude&lt;/code&gt; for the second one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Two Claude Desktop windows, free&lt;/td&gt;
&lt;td&gt;Start a second copy with &lt;code&gt;--user-data-dir&lt;/code&gt; (commands below)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Separate Dock icons, ‚åò-Tab, Google sign-in that lands in the right window, survives updates&lt;/td&gt;
&lt;td&gt;You need each account to be its own &lt;em&gt;app&lt;/em&gt;, not just its own folder (see "Why the hacks break")&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Claude Desktop can only hold one login
&lt;/h2&gt;

&lt;p&gt;Claude Desktop is an Electron app, so it's Chromium underneath. Everything for the signed-in account (session cookies, settings, connectors, MCP config, the list of Claude Code sessions) lives in one &lt;strong&gt;user data directory&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;macOS: &lt;code&gt;~/Library/Application Support/Claude&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;%APPDATA%\Claude&lt;/code&gt; (the Microsoft Store version redirects this into its package folder, under &lt;code&gt;%LOCALAPPDATA%\Packages\Claude_‚Ä¶\LocalCache\Roaming\Claude&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One folder, one cookie jar, one login. Signing in to account B overwrites account A's session.&lt;/p&gt;

&lt;p&gt;Your chats aren't lost when you switch; they live in your account on Anthropic's side. What you lose is time, context, and the ability to see both at once.&lt;/p&gt;

&lt;p&gt;So every working solution comes down to the same idea: &lt;strong&gt;give each account its own data directory.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Code (CLI): one environment variable
&lt;/h2&gt;

&lt;p&gt;The CLI is the easy part. It reads its login and settings from a config directory, which you can override:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# second account, one-off&lt;/span&gt;
&lt;span class="nv"&gt;CLAUDE_CONFIG_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/.claude-work claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it permanent with an alias in &lt;code&gt;~/.zshrc&lt;/code&gt; or &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;claude-work&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'CLAUDE_CONFIG_DIR="$HOME/.claude-work" claude'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;claude-personal&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'CLAUDE_CONFIG_DIR="$HOME/.claude-personal" claude'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;claude-work&lt;/code&gt; once, log in with the work account, done. Each folder keeps its own login, history and settings. This works the same on macOS, Linux and Windows (in PowerShell: &lt;code&gt;$env:CLAUDE_CONFIG_DIR="$HOME\.claude-work"; claude&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Desktop on macOS: a second copy, for free
&lt;/h2&gt;

&lt;p&gt;Chromium apps accept &lt;code&gt;--user-data-dir&lt;/code&gt;, and Claude Desktop honors it. This starts a second, independent Claude next to your normal one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;open &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; Claude &lt;span class="nt"&gt;--args&lt;/span&gt; &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/Claude-Work"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt; opens a new instance even though Claude is already running.&lt;/li&gt;
&lt;li&gt;Everything after &lt;code&gt;--args&lt;/code&gt; goes to Claude itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sign in to the second account in the new window. Wrap it in a shell function so you can have as many as you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.zshrc&lt;/span&gt;
claude-profile&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; claude-profile &amp;lt;name&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  open &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; Claude &lt;span class="nt"&gt;--args&lt;/span&gt; &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Library/Application Support/Claude-&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude-profile Work
claude-profile ClientA
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Want it clickable? Open &lt;strong&gt;Script Editor&lt;/strong&gt;, paste &lt;code&gt;do shell script "open -n -a Claude --args --user-data-dir=$HOME/Library/Application\\ Support/Claude-Work"&lt;/code&gt;, then &lt;strong&gt;File ‚Üí Export ‚Üí File Format: Application&lt;/strong&gt;. Drop it in the Dock.&lt;/p&gt;

&lt;p&gt;That's the whole free method, and for a lot of people it's enough. Now the part the copy-paste guides skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the hacks break (the interesting part)
&lt;/h2&gt;

&lt;p&gt;All of these come from one fact: &lt;strong&gt;to the operating system, both windows are still the same app.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. One Dock icon, one ‚åò-Tab entry
&lt;/h3&gt;

&lt;p&gt;macOS groups windows by bundle identifier (&lt;code&gt;com.anthropic.claudefordesktop&lt;/code&gt;). Your two instances share it, so they share a Dock icon, a name, and a single ‚åò-Tab slot. You can't tell which window is which account without looking inside it.&lt;/p&gt;

&lt;p&gt;A Script Editor launcher doesn't fix this. The launcher is its own app, but the Claude window it opens still belongs to Claude.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Google sign-in comes back to the wrong window
&lt;/h3&gt;

&lt;p&gt;This one costs people the most time. When you click &lt;strong&gt;Continue with Google&lt;/strong&gt;, Claude opens your browser. After you log in, the browser hands the result back through a &lt;code&gt;claude://&lt;/code&gt; link.&lt;/p&gt;

&lt;p&gt;The OS routes that link to &lt;em&gt;the app registered for &lt;code&gt;claude://&lt;/code&gt;&lt;/em&gt;, not to the specific window that started the login. With two instances of the same app, the link goes to whichever instance the OS picks, usually the first one. So you sign in to your work account and it lands in your personal window, or nowhere useful.&lt;/p&gt;

&lt;p&gt;On Windows it's even more deterministic. Chromium's single-instance logic means a new launch first checks for a lock file in the &lt;strong&gt;default&lt;/strong&gt; data folder; if that instance is running, the link gets forwarded to it. So the default &lt;code&gt;Claude&lt;/code&gt; window always wins.&lt;/p&gt;

&lt;p&gt;Workarounds: use email sign-in for the extra profiles, or quit every other Claude window while you sign in to the new one.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Claude Code sessions don't follow you
&lt;/h3&gt;

&lt;p&gt;The Code tab in Claude Desktop lists sessions from the data directory it's using. A fresh &lt;code&gt;Claude-Work&lt;/code&gt; folder starts empty, even if that account has sessions in your main Claude. They aren't gone; they're in the other folder. You'd have to copy the right ones over by hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. "Just copy Claude.app and rename it" doesn't survive updates
&lt;/h3&gt;

&lt;p&gt;The natural next step is duplicating &lt;code&gt;Claude.app&lt;/code&gt;, changing its bundle ID and name in &lt;code&gt;Info.plist&lt;/code&gt;, and re-signing it, so each account really is a separate app with its own Dock icon. That does fix #1.&lt;/p&gt;

&lt;p&gt;But Claude updates itself, and an update can bring back the original bundle or leave you with a copy that's stuck on an old version. Then you're redoing the copy, re-signing, and re-pointing it at the right data folder after every Claude release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Claude Desktop on Windows: the same trick
&lt;/h2&gt;

&lt;p&gt;Claude for Windows installs through the Microsoft Store, with a command alias you can call directly. In PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Start-Process&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;LOCALAPPDATA&lt;/span&gt;&lt;span class="s2"&gt;\Microsoft\WindowsApps\claude-desktop.exe"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--user-data-dir=&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;\ClaudeProfiles\Work&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same rules as on the Mac: each &lt;code&gt;--user-data-dir&lt;/code&gt; is a separate login. And the same gotchas apply:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All windows share one taskbar icon and the title "Claude".&lt;/li&gt;
&lt;li&gt;Google sign-in returns to the &lt;em&gt;default&lt;/em&gt; Claude window (see #2), so sign in to extra profiles with email, or close the main Claude first.&lt;/li&gt;
&lt;li&gt;If Claude's own "start with Windows" setting is on, the default instance is always running and always catches the sign-in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The other options, briefly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A second browser profile with claude.ai.&lt;/strong&gt; Totally fine for chatting. You lose the desktop-only features for that account: the Code tab, local MCP servers and desktop connectors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A second OS user account.&lt;/strong&gt; Fully isolated, including Claude Code. But you only see one user's desktop at a time, and none of your files or apps come along.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sign out and back in.&lt;/strong&gt; Free and built in. Fine weekly, painful hourly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apps that do it for you.&lt;/strong&gt; Parall (a general launcher for many apps, $9.99 in the Mac App Store), Multi-Claude ($20) and Claude Sessions Pro ($15) all turn each account into its own app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I built
&lt;/h2&gt;

&lt;p&gt;I got tired of doing all of the above by hand, so I built &lt;a href="https://doubleclaude.com" rel="noopener noreferrer"&gt;Claude Sessions Pro&lt;/a&gt; for macOS. It makes each account a real, separate Mac app built from your installed Claude, which is what fixes the gotchas above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Own app per account:&lt;/strong&gt; "Claude Work", "Claude Personal", each with a colored letter badge on its Dock icon and its own ‚åò-Tab spot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Google sign-in works with the other accounts still open&lt;/strong&gt;, and returns to the profile that asked for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code sessions and pins come along:&lt;/strong&gt; sessions from your main Claude move into the matching account's profile, and the CLI opens per profile with its own &lt;code&gt;CLAUDE_CONFIG_DIR&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Survives Claude updates:&lt;/strong&gt; when Claude updates, each profile app is rebuilt from the new version the next time it isn't running. Logins and data stay put.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menu bar switcher&lt;/strong&gt; to open or switch accounts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's $15 one-time for up to 2 computers, with a &lt;strong&gt;1-hour free preview&lt;/strong&gt; that starts once you've signed in to a profile. I'd rather you see it working with your own accounts before paying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Windows version is coming soon.&lt;/strong&gt; Same idea, built for Windows' quirks: it routes Google sign-in to the right window and labels every window with its account. If you want to know when it ships, &lt;a href="https://doubleclaude.com" rel="noopener noreferrer"&gt;doubleclaude.com&lt;/a&gt; is where it'll land.&lt;/p&gt;

&lt;p&gt;Here's the full comparison table with every method: &lt;a href="https://doubleclaude.com/run-multiple-claude-accounts-mac/" rel="noopener noreferrer"&gt;How to run multiple Claude accounts on one Mac&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is this allowed?
&lt;/h2&gt;

&lt;p&gt;Plenty of people have legitimate separate accounts: a company Team account plus a personal Pro one, or one per client. Everything above runs the official Claude app and doesn't change how Claude works.&lt;/p&gt;

&lt;p&gt;But Anthropic's terms apply to &lt;em&gt;each&lt;/em&gt; account. Creating extra accounts specifically to dodge usage limits is the kind of thing that gets accounts suspended. Read the Consumer Terms and Usage Policy, and only use accounts you're allowed to use.&lt;/p&gt;




&lt;p&gt;If you've found another approach (or another gotcha), drop it in the comments. I'm especially curious how people handle this on Linux, where Claude Desktop isn't official.&lt;/p&gt;

</description>
      <category>claude</category>
      <category>ai</category>
      <category>productivity</category>
      <category>macos</category>
    </item>
    <item>
      <title>Stop Instagram and TikTok labelling your Photoshop and Premiere exports as AI</title>
      <dc:creator>Sebastian Balog</dc:creator>
      <pubDate>Mon, 05 Oct 2026 01:58:20 +0000</pubDate>
      <link>https://dev.to/sebastian_balog_c88dc2913/stop-instagram-and-tiktok-labelling-your-photoshop-and-premiere-exports-as-ai-27lk</link>
      <guid>https://dev.to/sebastian_balog_c88dc2913/stop-instagram-and-tiktok-labelling-your-photoshop-and-premiere-exports-as-ai-27lk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick fix:&lt;/strong&gt; the label comes from Content Credentials (C2PA) that Photoshop and Premiere Pro write into your export after a generative edit, and export settings don't switch them off. Check every file as it lands in your export folder and remove those credentials before posting: below is a free script that does it, and &lt;a href="https://metacleanai.com/remove-metadata-photoshop/" rel="noopener noreferrer"&gt;an app that does it for you&lt;/a&gt; on Mac and Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your exports get labelled
&lt;/h2&gt;

&lt;p&gt;If you edit for clients or post every day, the "AI info" problem isn't one photo. It's every export. One Generative Fill in Photoshop or two seconds of Generative Extend in Premiere Pro, and the file you deliver carries &lt;strong&gt;Content Credentials (C2PA)&lt;/strong&gt; that Instagram, Facebook, TikTok, YouTube and LinkedIn read and turn into a label.&lt;/p&gt;

&lt;p&gt;Adobe's own FAQ says that when its generative tools create or modify content, C2PA metadata is attached automatically and can't be switched off for that content. Photoshop's &lt;em&gt;Export As → Metadata: None&lt;/em&gt; controls camera and copyright info, not that record. So the dependable place to check is &lt;strong&gt;the exported file&lt;/strong&gt;, right after it lands in your export folder.&lt;/p&gt;

&lt;p&gt;Here's how to automate that check yourself, and the gotchas that make it harder than it looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look for
&lt;/h2&gt;

&lt;p&gt;Two markers do almost all the labelling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;C2PA manifest&lt;/strong&gt;: JUMBF boxes labelled &lt;code&gt;c2pa&lt;/code&gt; (in JPEG they sit in &lt;code&gt;APP11&lt;/code&gt; segments; in MP4/MOV in a top-level &lt;code&gt;uuid&lt;/code&gt; box).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IPTC digital source type&lt;/strong&gt;: &lt;code&gt;Iptc4xmpExt:DigitalSourceType&lt;/code&gt; set to &lt;code&gt;trainedAlgorithmicMedia&lt;/code&gt; or &lt;code&gt;compositeWithTrainedAlgorithmicMedia&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quick check for one file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;c2patool &lt;span class="s2"&gt;"export.jpg"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"C2PA manifest present"&lt;/span&gt;
exiftool &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-if&lt;/span&gt; &lt;span class="s1"&gt;'$XMP-iptcExt:DigitalSourceType =~ /TrainedAlgorithmic/i'&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s1"&gt;'$FileName: AI source tag'&lt;/span&gt; &lt;span class="s2"&gt;"export.jpg"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A DIY watcher (macOS, fswatch)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# watch-exports.sh: flag new exports that carry AI metadata&lt;/span&gt;
&lt;span class="c"&gt;# needs: brew install fswatch exiftool c2patool&lt;/span&gt;
&lt;span class="nv"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/Exports&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

settled&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;               &lt;span class="c"&gt;# wait until the editor has finished writing&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; a b
  &lt;span class="k"&gt;while&lt;/span&gt; :&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; %z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
    &lt;span class="nb"&gt;sleep &lt;/span&gt;2
    &lt;span class="nv"&gt;b&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; %z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;1
    &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$a&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;return &lt;/span&gt;0
  &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

check&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;hits&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
  c2patool &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; hits+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"C2PA"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  exiftool &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-if&lt;/span&gt; &lt;span class="s1"&gt;'$XMP-iptcExt:DigitalSourceType =~ /TrainedAlgorithmic/i'&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; x &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; hits+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"IPTC AI tag"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="k"&gt;${#&lt;/span&gt;&lt;span class="nv"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;osascript &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"display notification &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;[*]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; with title &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;AI metadata: &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

fswatch &lt;span class="nt"&gt;-0&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'.*'&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'\.(jpe?g|png|mp4|mov)$'&lt;/span&gt; &lt;span class="nt"&gt;--event&lt;/span&gt; Created &lt;span class="nt"&gt;--event&lt;/span&gt; Updated &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; |
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; f&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; clean_&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;continue
  &lt;/span&gt;settled &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; check &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works, and it's a good way to see how often your exports actually carry these markers. The parts that take the most care:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Finished writing" is the hard part.&lt;/strong&gt; Premiere and Media Encoder write large files over minutes; Photoshop writes a temp file and renames it. The size-stable loop above is the simplest heuristic; a render that pauses mid-write can still fool it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recursion and noise.&lt;/strong&gt; Editors create sidecar and cache files; filter by extension and ignore your own &lt;code&gt;clean_&lt;/code&gt; outputs or you'll loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cleaning without damage.&lt;/strong&gt; The naive &lt;code&gt;exiftool -all=&lt;/code&gt; also deletes the colour profile and orientation. Use &lt;code&gt;exiftool -all= -tagsfromfile @ -icc_profile -orientation file.jpg&lt;/code&gt; for photos, and a stream-copy remux for video: &lt;code&gt;ffmpeg -i in.mp4 -map 0 -c copy -map_metadata -1 out.mp4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifying.&lt;/strong&gt; Re-run the checks on the output (&lt;code&gt;c2patool&lt;/code&gt; should say &lt;em&gt;No claim found&lt;/em&gt;), and for video compare &lt;code&gt;ffmpeg -f streamhash&lt;/code&gt; of input and output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows.&lt;/strong&gt; No fswatch; you'd rebuild this around PowerShell's &lt;code&gt;FileSystemWatcher&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The app version
&lt;/h2&gt;

&lt;p&gt;I got tired of maintaining scripts like this, so it became a feature in &lt;a href="https://metacleanai.com/remove-metadata-photoshop/" rel="noopener noreferrer"&gt;MetaClean&lt;/a&gt;, my Mac and Windows metadata app. &lt;strong&gt;Watch Folders&lt;/strong&gt; runs in the background on your export folders, subfolders included. Every new JPG, PNG, MP4 or MOV is checked once it has finished saving, whether it came from Photoshop, Lightroom, &lt;a href="https://metacleanai.com/premiere-pro-ai-label/" rel="noopener noreferrer"&gt;Premiere Pro or Media Encoder&lt;/a&gt;, CapCut or was just copied in. Files without AI metadata never interrupt you. When one carries Content Credentials or an AI-origin tag, a compact prompt lists what was found, and &lt;strong&gt;Clean&lt;/strong&gt; saves a verified &lt;code&gt;clean_&lt;/code&gt; copy next to the original: no re-encoding, colour profile and orientation kept, video streams copied as they are. For existing archives there's a batch mode for whole folders. Everything stays on your machine. 3-day free trial, then $5 once.&lt;/p&gt;

&lt;p&gt;Disclosure: I'm the developer of MetaClean.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generative edits in Photoshop and Premiere attach C2PA automatically; export settings don't remove it.&lt;/li&gt;
&lt;li&gt;Check exports with &lt;code&gt;c2patool&lt;/code&gt; and the IPTC &lt;code&gt;DigitalSourceType&lt;/code&gt; tag.&lt;/li&gt;
&lt;li&gt;Automate with a folder watcher, but handle "file finished", recursion, safe cleaning and verification.&lt;/li&gt;
&lt;li&gt;Or let &lt;a href="https://metacleanai.com/remove-metadata-photoshop/" rel="noopener noreferrer"&gt;MetaClean's Watch Folders&lt;/a&gt; do it on Mac and Windows.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>photography</category>
      <category>video</category>
      <category>automation</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to remove the "AI-generated" label from your TikTok videos (CapCut fix)</title>
      <dc:creator>Sebastian Balog</dc:creator>
      <pubDate>Mon, 05 Oct 2026 01:57:49 +0000</pubDate>
      <link>https://dev.to/sebastian_balog_c88dc2913/how-to-remove-the-ai-generated-label-from-your-tiktok-videos-capcut-fix-9op</link>
      <guid>https://dev.to/sebastian_balog_c88dc2913/how-to-remove-the-ai-generated-label-from-your-tiktok-videos-capcut-fix-9op</guid>
      <description>&lt;p&gt;&lt;strong&gt;Quick fix:&lt;/strong&gt; TikTok reads AI metadata inside the MP4, not your footage. Delete the labelled post, strip the metadata from your original export with one &lt;code&gt;ffmpeg&lt;/code&gt; command (below, no re-encoding) or with &lt;a href="https://metacleanai.com/remove-ai-generated-label-tiktok/" rel="noopener noreferrer"&gt;MetaClean&lt;/a&gt;, and repost the clean copy with the AI-generated content switch off.&lt;/p&gt;

&lt;p&gt;Here's why it happens, how to see it in your own files, and how to prove the fix didn't touch quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your real video got labelled
&lt;/h2&gt;

&lt;p&gt;You film something yourself, add one AI effect in CapCut, export, post, and TikTok puts &lt;strong&gt;"AI-generated"&lt;/strong&gt; on it. The footage is yours. The label disagrees.&lt;/p&gt;

&lt;p&gt;Like Instagram's "AI info", TikTok's automatic label is mostly a &lt;strong&gt;metadata&lt;/strong&gt; decision. TikTok has said it reads &lt;a href="https://newsroom.tiktok.com/en-us/partnering-with-our-industry-to-advance-ai-transparency-and-literacy" rel="noopener noreferrer"&gt;Content Credentials (C2PA)&lt;/a&gt; to label AI content automatically, and editing apps write AI markers into the files they export after an AI feature is used. So the useful question isn't "what does the video look like?" but "what does the MP4 say about itself?"&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the label comes from
&lt;/h2&gt;

&lt;p&gt;TikTok adds "AI-generated" in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You switch it on&lt;/strong&gt; in the post settings ("AI-generated content").&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatically&lt;/strong&gt;, when the uploaded file carries AI metadata.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second one is the surprise. Typical sources:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App or feature&lt;/th&gt;
&lt;th&gt;What you did&lt;/th&gt;
&lt;th&gt;What ends up in the file&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CapCut AI features&lt;/td&gt;
&lt;td&gt;AI effects, enhancements, generated elements&lt;/td&gt;
&lt;td&gt;AI metadata in the export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Premiere Pro Generative Extend&lt;/td&gt;
&lt;td&gt;Stretched a clip by a few frames&lt;/td&gt;
&lt;td&gt;C2PA Content Credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI video generators&lt;/td&gt;
&lt;td&gt;B-roll, backgrounds, intros&lt;/td&gt;
&lt;td&gt;C2PA Content Credentials&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI upscalers / enhancers&lt;/td&gt;
&lt;td&gt;Sharpen, stabilise, upscale&lt;/td&gt;
&lt;td&gt;C2PA or IPTC, depending on the app&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One AI touch is enough for the whole video, because the note describes the file, not the frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look inside the MP4
&lt;/h2&gt;

&lt;p&gt;An MP4 is a tree of boxes (atoms). Regular metadata lives in &lt;code&gt;moov/udta&lt;/code&gt; and &lt;code&gt;meta&lt;/code&gt;; a C2PA manifest is stored as its own JUMBF payload in a top-level &lt;code&gt;uuid&lt;/code&gt; box, next to the audio and video data rather than inside it. That's why the usual "Properties → Details" view doesn't show it.&lt;/p&gt;

&lt;p&gt;Dump everything ExifTool can see, grouped by where it lives:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-G1&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; clip.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for the encoder and creation tool (&lt;code&gt;Encoder&lt;/code&gt;, &lt;code&gt;Software&lt;/code&gt;, &lt;code&gt;HandlerVendorID&lt;/code&gt;), any XMP block, and anything mentioning AI, AIGC or C2PA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-G1&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; clip.mp4 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'c2pa|jumd|aigc|digitalsource|encoder|software'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the signed manifest itself, the official &lt;a href="https://github.com/contentauth/c2pa-rs" rel="noopener noreferrer"&gt;c2patool&lt;/a&gt; reads MP4 and MOV directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;c2patool clip.mp4
&lt;span class="c"&gt;# prints the manifest: claim generator, actions, digitalSourceType...&lt;/span&gt;
&lt;span class="c"&gt;# or "No claim found" if there is none&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And while you're in there, check the stuff you probably didn't mean to share: phones write a recording location and the device model into the &lt;code&gt;udta&lt;/code&gt; atoms.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-GPSCoordinates&lt;/span&gt; &lt;span class="nt"&gt;-Model&lt;/span&gt; &lt;span class="nt"&gt;-Make&lt;/span&gt; &lt;span class="nt"&gt;-CreationDate&lt;/span&gt; clip.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Removing it without re-encoding
&lt;/h2&gt;

&lt;p&gt;Re-exporting the video to "shake off" metadata costs quality and often writes the same markers again. The clean way is a &lt;strong&gt;remux&lt;/strong&gt;: copy the existing video and audio streams into a new container and leave the metadata boxes behind.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; clip.mp4 &lt;span class="nt"&gt;-map&lt;/span&gt; 0 &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-map_metadata&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;-movflags&lt;/span&gt; +faststart clean.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-c copy&lt;/code&gt; means no decoding and no re-encoding: same frames, same bitrate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-map_metadata -1&lt;/code&gt; drops the global metadata (including the location and device atoms).&lt;/li&gt;
&lt;li&gt;The C2PA &lt;code&gt;uuid&lt;/code&gt; box isn't carried over by the remux.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+faststart&lt;/code&gt; moves the index to the front, which upload pipelines like.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then prove it, because a clean-looking command isn't proof:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;c2patool clean.mp4                    &lt;span class="c"&gt;# should say: No claim found&lt;/span&gt;
exiftool &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-G1&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; clean.mp4 | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-iE&lt;/span&gt; &lt;span class="s1"&gt;'c2pa|jumd|aigc|gps'&lt;/span&gt;   &lt;span class="c"&gt;# should print nothing&lt;/span&gt;

&lt;span class="c"&gt;# and the streams are bit-for-bit identical:&lt;/span&gt;
ffmpeg &lt;span class="nt"&gt;-loglevel&lt;/span&gt; error &lt;span class="nt"&gt;-i&lt;/span&gt; clip.mp4  &lt;span class="nt"&gt;-map&lt;/span&gt; 0 &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-f&lt;/span&gt; streamhash &lt;span class="nt"&gt;-hash&lt;/span&gt; sha256 -
ffmpeg &lt;span class="nt"&gt;-loglevel&lt;/span&gt; error &lt;span class="nt"&gt;-i&lt;/span&gt; clean.mp4 &lt;span class="nt"&gt;-map&lt;/span&gt; 0 &lt;span class="nt"&gt;-c&lt;/span&gt; copy &lt;span class="nt"&gt;-f&lt;/span&gt; streamhash &lt;span class="nt"&gt;-hash&lt;/span&gt; sha256 -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the two &lt;code&gt;streamhash&lt;/code&gt; outputs match, the picture and sound are exactly what you exported.&lt;/p&gt;

&lt;p&gt;Then repost: delete the labelled post (copy the caption and note the sound first), upload &lt;code&gt;clean.mp4&lt;/code&gt;, and leave the AI-generated content switch off.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you export from CapCut every day
&lt;/h2&gt;

&lt;p&gt;Doing this per clip gets old fast. I built &lt;a href="https://metacleanai.com/remove-ai-generated-label-tiktok/" rel="noopener noreferrer"&gt;MetaClean&lt;/a&gt; for that: a Mac and Windows app that shows every piece of metadata in a video (or photo) in plain words, removes the AI markers, or location and device details too, and saves a verified &lt;code&gt;clean_&lt;/code&gt; copy next to the original, using the same stream-copy approach as above. Its &lt;strong&gt;Watch Folders&lt;/strong&gt; mode sits on your CapCut export folder (subfolders included) and only pops up when a new export actually carries AI metadata: one click and the clean copy is ready to post. Everything runs locally; nothing is uploaded. 3-day free trial, then $5 once.&lt;/p&gt;

&lt;p&gt;Disclosure: I'm the developer of MetaClean.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;TikTok's automatic "AI-generated" label is read from the file's metadata, including C2PA Content Credentials.&lt;/li&gt;
&lt;li&gt;See it: &lt;code&gt;c2patool clip.mp4&lt;/code&gt; and &lt;code&gt;exiftool -a -G1 -s clip.mp4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Remove it without touching quality: &lt;code&gt;ffmpeg -i clip.mp4 -map 0 -c copy -map_metadata -1 clean.mp4&lt;/code&gt;, then verify with &lt;code&gt;c2patool&lt;/code&gt; and &lt;code&gt;streamhash&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Full TikTok walkthrough: &lt;a href="https://metacleanai.com/remove-ai-generated-label-tiktok/" rel="noopener noreferrer"&gt;How to remove the AI-generated label on TikTok&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>privacy</category>
      <category>video</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Why Instagram labels your real photo "AI info" (and how to see the metadata behind it)</title>
      <dc:creator>Sebastian Balog</dc:creator>
      <pubDate>Sat, 26 Sep 2026 20:46:48 +0000</pubDate>
      <link>https://dev.to/sebastian_balog_c88dc2913/why-instagram-labels-your-real-photo-ai-info-and-how-to-see-the-metadata-behind-it-4j0f</link>
      <guid>https://dev.to/sebastian_balog_c88dc2913/why-instagram-labels-your-real-photo-ai-info-and-how-to-see-the-metadata-behind-it-4j0f</guid>
      <description>&lt;p&gt;You take a real photo, remove a stray object with a generative fill tool, post it, and Instagram adds &lt;strong&gt;"AI info"&lt;/strong&gt; under your name. The picture is 99% camera, but the label says otherwise.&lt;/p&gt;

&lt;p&gt;The label usually isn't about the pixels. It's about &lt;strong&gt;metadata&lt;/strong&gt; the editing tool wrote into the file. Once you know where it lives, you can see it in seconds, and remove it without touching the image.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the platforms read
&lt;/h2&gt;

&lt;p&gt;Meta has said it labels images using industry-standard signals in the file. Two of them do most of the work:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. C2PA Content Credentials.&lt;/strong&gt; A signed manifest embedded in the file (in a JPEG it sits in &lt;code&gt;APP11&lt;/code&gt; segments as JUMBF boxes). It records which app made or edited the image and what it did: &lt;code&gt;c2pa.opened&lt;/code&gt;, &lt;code&gt;c2pa.edited&lt;/code&gt;, and, for AI tools, a &lt;code&gt;digitalSourceType&lt;/code&gt; saying generative AI was involved. Photoshop, Firefly, ChatGPT's image generation and a growing list of phones and cameras write it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The IPTC digital source type.&lt;/strong&gt; A single XMP field, &lt;code&gt;Iptc4xmpExt:DigitalSourceType&lt;/code&gt;, whose value is a URL from the IPTC vocabulary. The two that matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;trainedAlgorithmicMedia&lt;/code&gt;: made with generative AI&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;compositeWithTrainedAlgorithmicMedia&lt;/code&gt;: edited with generative AI (your generative-fill case)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Either one is enough to earn the label.&lt;/p&gt;

&lt;h2&gt;
  
  
  See it in your own files
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://exiftool.org" rel="noopener noreferrer"&gt;ExifTool&lt;/a&gt; installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# The IPTC AI tag&lt;/span&gt;
exiftool &lt;span class="nt"&gt;-XMP-iptcExt&lt;/span&gt;:DigitalSourceType photo.jpg
&lt;span class="c"&gt;# Digital Source Type : http://cv.iptc.org/newscodes/digitalsourcetype/compositeWithTrainedAlgorithmicMedia&lt;/span&gt;

&lt;span class="c"&gt;# Is there a C2PA manifest? (JUMBF boxes labelled c2pa)&lt;/span&gt;
exiftool &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-JUMDLabel&lt;/span&gt; photo.jpg
&lt;span class="c"&gt;# JUMD Label : c2pa&lt;/span&gt;
&lt;span class="c"&gt;# JUMD Label : urn:c2pa:060ce687-...&lt;/span&gt;
&lt;span class="c"&gt;# JUMD Label : c2pa.assertions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the full, human-readable manifest (signer, actions, validation state), use the official &lt;a href="https://github.com/contentauth/c2pa-rs" rel="noopener noreferrer"&gt;c2patool&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;c2patool photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While you're in there, check what else the file carries. Most phones add GPS once the camera has location access:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-GPSPosition&lt;/span&gt; &lt;span class="nt"&gt;-Model&lt;/span&gt; &lt;span class="nt"&gt;-SerialNumber&lt;/span&gt; photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No command line handy? I built a free &lt;a href="https://metacleanai.com/exif-viewer/" rel="noopener noreferrer"&gt;in-browser EXIF and C2PA viewer&lt;/a&gt; that reads all of this, including the prompts Stable Diffusion and ComfyUI hide in PNGs. The file is read locally and never uploaded; switch off your Wi-Fi after the page loads and it still works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Removing it (and the gotcha that bites everyone)
&lt;/h2&gt;

&lt;p&gt;The classic one-liner does remove the C2PA manifest, the IPTC tag and your GPS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-all&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But run it on a photo from a phone and look closely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Warning: ICC_Profile deleted. Image colors may be affected - photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-all=&lt;/code&gt; also deletes the &lt;strong&gt;colour profile&lt;/strong&gt; and the &lt;strong&gt;orientation&lt;/strong&gt; flag. iPhone photos are usually Display P3, so they come out duller, and portrait shots can come out sideways. The fix is to copy those two back from the original in the same command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-all&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nt"&gt;-tagsfromfile&lt;/span&gt; @ &lt;span class="nt"&gt;-icc_profile&lt;/span&gt; &lt;span class="nt"&gt;-orientation&lt;/span&gt; photo.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested both on a C2PA-signed, Display P3, rotated JPEG: the second command removed the manifest (&lt;code&gt;c2patool&lt;/code&gt; reports &lt;code&gt;No claim found&lt;/code&gt;), the IPTC tag and the GPS, kept the profile and rotation, and left the decoded pixels identical.&lt;/p&gt;

&lt;p&gt;Then check your result, because a clean-looking command isn't proof:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;exiftool &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;-JUMDLabel&lt;/span&gt; &lt;span class="nt"&gt;-XMP-iptcExt&lt;/span&gt;:DigitalSourceType &lt;span class="nt"&gt;-GPSPosition&lt;/span&gt; photo.jpg   &lt;span class="c"&gt;# should print nothing&lt;/span&gt;
c2patool photo.jpg                                                             &lt;span class="c"&gt;# should say No claim found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the label is already on a post, removing the metadata from your file isn't enough on its own: Instagram keeps the label on what it already published. I wrote up the full repost routine for feed posts, Reels, Stories and Facebook (including saving your caption first) in &lt;a href="https://metacleanai.com/remove-ai-info-instagram/" rel="noopener noreferrer"&gt;How to remove AI info from Instagram posts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doing this for a whole camera roll
&lt;/h2&gt;

&lt;p&gt;For one JPEG, the ExifTool commands above are all you need. For folders full of photos &lt;em&gt;and&lt;/em&gt; videos (where metadata lives in QuickTime atoms and its own C2PA box), I made &lt;a href="https://metacleanai.com/" rel="noopener noreferrer"&gt;MetaClean&lt;/a&gt;, a Mac and Windows app that does the whole thing offline. It bundles pinned versions of ExifTool, c2patool and FFmpeg, never re-encodes (video is remuxed with stream copy), keeps colour profiles and orientation, and re-inspects every output before saving it as &lt;code&gt;clean_&amp;lt;name&amp;gt;&lt;/code&gt;, leaving the original untouched. There's a 3-day free trial, then it's $5 once.&lt;/p&gt;

&lt;p&gt;Disclosure: I'm the developer of MetaClean and the viewer linked above.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;"AI info" on a real photo usually comes from &lt;strong&gt;C2PA Content Credentials&lt;/strong&gt; or the &lt;strong&gt;IPTC DigitalSourceType&lt;/strong&gt; tag, not from the pixels.&lt;/li&gt;
&lt;li&gt;See them: &lt;code&gt;exiftool -XMP-iptcExt:DigitalSourceType -a -JUMDLabel photo.jpg&lt;/code&gt;, or &lt;code&gt;c2patool photo.jpg&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Remove them without breaking the photo: &lt;code&gt;exiftool -all= -tagsfromfile @ -icc_profile -orientation photo.jpg&lt;/code&gt;, then verify.&lt;/li&gt;
&lt;li&gt;Already labelled? See &lt;a href="https://metacleanai.com/remove-ai-info-instagram/" rel="noopener noreferrer"&gt;how to remove AI info from Instagram&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>privacy</category>
      <category>photography</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
