Created
December 31, 2025 13:13
-
-
Save ShawnaRStaff/2841cce99928bd5436ed908cc7633d33 to your computer and use it in GitHub Desktop.
delete x media
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Standalone script to delete all media tweets | |
| // Run this on x.com (any page while logged in) | |
| var authorization = "Bearer "; | |
| var client_tid = ""; | |
| var random_resource_media = ""; | |
| var username = ""; | |
| var ua = navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', '); | |
| var client_uuid = crypto.randomUUID(); | |
| var csrf_token = document.cookie.split('; ').find(row => row.startsWith('ct0=')).split('=')[1]; | |
| var user_id = decodeURIComponent(document.cookie.split('; ').find(row => row.startsWith('twid=')).split('=')[1]).substring(2); | |
| var language_code = navigator.language.split("-")[0]; | |
| async function sleep(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| function buildAcceptLanguageString() { | |
| const languages = navigator.languages; | |
| if (!languages || languages.length === 0) return "en-US,en;q=0.9"; | |
| let q = 1; | |
| return languages.map(lang => { | |
| if (q < 1) { | |
| const result = `${lang};q=${q.toFixed(1)}`; | |
| q -= 0.1; | |
| return result; | |
| } | |
| q -= 0.1; | |
| return lang; | |
| }).join(','); | |
| } | |
| async function fetch_media(cursor, retry = 0) { | |
| let count = "20"; | |
| let final_cursor = cursor ? `%22cursor%22%3A%22${cursor}%22%2C` : ""; | |
| var base_url = `https://x.com/i/api/graphql/${random_resource_media}/UserMedia`; | |
| var variable = `?variables=%7B%22userId%22%3A%22${user_id}%22%2C%22count%22%3A${count}%2C${final_cursor}%22includePromotedContent%22%3Afalse%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%7D`; | |
| var feature = `&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22responsive_web_profile_redirect_enabled%22%3Afalse%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Atrue%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Atrue%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_grok_imagine_annotation_enabled%22%3Atrue%2C%22responsive_web_grok_community_note_auto_translation_is_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D`; | |
| const response = await fetch(base_url + variable + feature, { | |
| headers: { | |
| "accept": "*/*", | |
| "accept-language": buildAcceptLanguageString(), | |
| "authorization": authorization, | |
| "content-type": "application/json", | |
| "x-client-transaction-id": client_tid, | |
| "x-client-uuid": client_uuid, | |
| "x-csrf-token": csrf_token, | |
| "x-twitter-active-user": "yes", | |
| "x-twitter-auth-type": "OAuth2Session", | |
| "x-twitter-client-language": language_code | |
| }, | |
| credentials: "include" | |
| }); | |
| if (!response.ok) { | |
| if (response.status === 429) { | |
| console.log("Rate limit reached. Waiting 1 minute..."); | |
| await sleep(60000); | |
| return fetch_media(cursor, retry + 1); | |
| } | |
| if (retry >= 5) throw new Error("Max retries reached fetching media"); | |
| console.log(`Fetch error (${response.status}), retrying in ${10 * (1 + retry)}s...`); | |
| await sleep(10000 * (1 + retry)); | |
| return fetch_media(cursor, retry + 1); | |
| } | |
| const data = await response.json(); | |
| let entries = data?.data?.user?.result?.timeline_v2?.timeline?.instructions | |
| || data?.data?.user?.result?.timeline?.timeline?.instructions; | |
| if (!entries) { | |
| console.log("Response:", data); | |
| throw new Error("Could not parse media response"); | |
| } | |
| for (let item of entries) { | |
| if (item.type === "TimelineAddEntries") { | |
| console.log("Raw entries:", item.entries.map(e => e.entryId)); | |
| return item.entries; | |
| } | |
| } | |
| console.log("No TimelineAddEntries found. Instructions:", entries.map(e => e.type)); | |
| return []; | |
| } | |
| async function delete_tweet(tweet_id, retry = 0) { | |
| const response = await fetch("https://x.com/i/api/graphql/VaenaVgh5q5ih7kvyVjgtg/DeleteTweet", { | |
| method: "POST", | |
| headers: { | |
| "accept": "*/*", | |
| "accept-language": buildAcceptLanguageString(), | |
| "authorization": authorization, | |
| "content-type": "application/json", | |
| "x-client-transaction-id": client_tid, | |
| "x-client-uuid": client_uuid, | |
| "x-csrf-token": csrf_token, | |
| "x-twitter-active-user": "yes", | |
| "x-twitter-auth-type": "OAuth2Session", | |
| "x-twitter-client-language": language_code | |
| }, | |
| body: JSON.stringify({ | |
| variables: { tweet_id: tweet_id, dark_request: false }, | |
| queryId: "VaenaVgh5q5ih7kvyVjgtg" | |
| }), | |
| credentials: "include" | |
| }); | |
| if (!response.ok) { | |
| if (response.status === 429) { | |
| console.log("Rate limit on delete. Waiting 1 minute..."); | |
| await sleep(60000); | |
| return delete_tweet(tweet_id, retry + 1); | |
| } | |
| if (retry >= 3) { | |
| console.log(`Failed to delete ${tweet_id} after retries`); | |
| return false; | |
| } | |
| await sleep(5000); | |
| return delete_tweet(tweet_id, retry + 1); | |
| } | |
| return true; | |
| } | |
| // Main execution | |
| (async function() { | |
| console.log("🚀 Starting to delete all media tweets..."); | |
| console.log("User ID:", user_id); | |
| let totalDeleted = 0; | |
| let rounds = 0; | |
| let emptyRounds = 0; | |
| const maxEmptyRounds = 3; // Stop after 3 consecutive empty fetches | |
| while (emptyRounds < maxEmptyRounds) { | |
| rounds++; | |
| console.log(`\n=== Round ${rounds} ===`); | |
| // Always start fresh (no cursor) to get current media | |
| console.log("Fetching media tweets..."); | |
| const entries = await fetch_media(null); | |
| // Find tweet IDs | |
| let tweetIds = []; | |
| for (const entry of entries) { | |
| if (entry.entryId.startsWith("tweet-")) { | |
| tweetIds.push(entry.entryId.replace("tweet-", "")); | |
| } else if (entry.entryId.startsWith("profile-grid-")) { | |
| const items = entry.content?.items || []; | |
| console.log(`Found ${items.length} items in profile-grid`); | |
| for (const item of items) { | |
| const itemId = item.item?.itemContent?.tweet_results?.result?.rest_id | |
| || item.item?.itemContent?.tweet_results?.result?.tweet?.rest_id | |
| || item.item?.itemContent?.tweet_results?.result?.legacy?.id_str; | |
| if (itemId) { | |
| tweetIds.push(itemId); | |
| } | |
| } | |
| } | |
| } | |
| console.log(`Found ${tweetIds.length} media tweets to delete`); | |
| if (tweetIds.length === 0) { | |
| emptyRounds++; | |
| console.log(`No media found (empty round ${emptyRounds}/${maxEmptyRounds})`); | |
| await sleep(3000); | |
| continue; | |
| } | |
| emptyRounds = 0; // Reset empty counter when we find tweets | |
| // Delete each tweet | |
| for (let i = 0; i < tweetIds.length; i++) { | |
| const success = await delete_tweet(tweetIds[i]); | |
| if (success) { | |
| totalDeleted++; | |
| console.log(`Deleted ${totalDeleted}: ${tweetIds[i]}`); | |
| } else { | |
| console.log(`Failed to delete: ${tweetIds[i]}`); | |
| } | |
| await sleep(150); | |
| } | |
| console.log(`Round ${rounds} complete. Total deleted so far: ${totalDeleted}`); | |
| await sleep(2000); | |
| } | |
| console.log(`\n✅ ALL DONE! Deleted ${totalDeleted} media tweets in ${rounds} rounds.`); | |
| })(); | |
| // Standalone script to delete all media tweets | |
| // Run this on x.com (any page while logged in) | |
| var authorization = "Bearer "; | |
| var client_tid = ""; | |
| var random_resource_media = ""; | |
| var username = ""; | |
| var ua = navigator.userAgentData.brands.map(brand => `"${brand.brand}";v="${brand.version}"`).join(', '); | |
| var client_uuid = crypto.randomUUID(); | |
| var csrf_token = document.cookie.split('; ').find(row => row.startsWith('ct0=')).split('=')[1]; | |
| var user_id = decodeURIComponent(document.cookie.split('; ').find(row => row.startsWith('twid=')).split('=')[1]).substring(2); | |
| var language_code = navigator.language.split("-")[0]; | |
| async function sleep(ms) { | |
| return new Promise(resolve => setTimeout(resolve, ms)); | |
| } | |
| function buildAcceptLanguageString() { | |
| const languages = navigator.languages; | |
| if (!languages || languages.length === 0) return "en-US,en;q=0.9"; | |
| let q = 1; | |
| return languages.map(lang => { | |
| if (q < 1) { | |
| const result = `${lang};q=${q.toFixed(1)}`; | |
| q -= 0.1; | |
| return result; | |
| } | |
| q -= 0.1; | |
| return lang; | |
| }).join(','); | |
| } | |
| async function fetch_media(cursor, retry = 0) { | |
| let count = "20"; | |
| let final_cursor = cursor ? `%22cursor%22%3A%22${cursor}%22%2C` : ""; | |
| var base_url = `https://x.com/i/api/graphql/${random_resource_media}/UserMedia`; | |
| var variable = `?variables=%7B%22userId%22%3A%22${user_id}%22%2C%22count%22%3A${count}%2C${final_cursor}%22includePromotedContent%22%3Afalse%2C%22withClientEventToken%22%3Afalse%2C%22withBirdwatchNotes%22%3Afalse%2C%22withVoice%22%3Atrue%7D`; | |
| var feature = `&features=%7B%22rweb_video_screen_enabled%22%3Afalse%2C%22profile_label_improvements_pcf_label_in_post_enabled%22%3Atrue%2C%22responsive_web_profile_redirect_enabled%22%3Afalse%2C%22rweb_tipjar_consumption_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Atrue%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22premium_content_api_read_enabled%22%3Afalse%2C%22communities_web_enable_tweet_community_results_fetch%22%3Atrue%2C%22c9s_tweet_anatomy_moderator_badge_enabled%22%3Atrue%2C%22responsive_web_grok_analyze_button_fetch_trends_enabled%22%3Afalse%2C%22responsive_web_grok_analyze_post_followups_enabled%22%3Atrue%2C%22responsive_web_jetfuel_frame%22%3Atrue%2C%22responsive_web_grok_share_attachment_enabled%22%3Atrue%2C%22articles_preview_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22responsive_web_twitter_article_tweet_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22responsive_web_grok_show_grok_translated_post%22%3Atrue%2C%22responsive_web_grok_analysis_button_from_backend%22%3Atrue%2C%22creator_subscriptions_quote_tweet_preview_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Atrue%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Atrue%2C%22longform_notetweets_rich_text_read_enabled%22%3Atrue%2C%22longform_notetweets_inline_media_enabled%22%3Atrue%2C%22responsive_web_grok_image_annotation_enabled%22%3Atrue%2C%22responsive_web_grok_imagine_annotation_enabled%22%3Atrue%2C%22responsive_web_grok_community_note_auto_translation_is_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%7D&fieldToggles=%7B%22withArticlePlainText%22%3Afalse%7D`; | |
| const response = await fetch(base_url + variable + feature, { | |
| headers: { | |
| "accept": "*/*", | |
| "accept-language": buildAcceptLanguageString(), | |
| "authorization": authorization, | |
| "content-type": "application/json", | |
| "x-client-transaction-id": client_tid, | |
| "x-client-uuid": client_uuid, | |
| "x-csrf-token": csrf_token, | |
| "x-twitter-active-user": "yes", | |
| "x-twitter-auth-type": "OAuth2Session", | |
| "x-twitter-client-language": language_code | |
| }, | |
| credentials: "include" | |
| }); | |
| if (!response.ok) { | |
| if (response.status === 429) { | |
| console.log("Rate limit reached. Waiting 1 minute..."); | |
| await sleep(60000); | |
| return fetch_media(cursor, retry + 1); | |
| } | |
| if (retry >= 5) throw new Error("Max retries reached fetching media"); | |
| console.log(`Fetch error (${response.status}), retrying in ${10 * (1 + retry)}s...`); | |
| await sleep(10000 * (1 + retry)); | |
| return fetch_media(cursor, retry + 1); | |
| } | |
| const data = await response.json(); | |
| let entries = data?.data?.user?.result?.timeline_v2?.timeline?.instructions | |
| || data?.data?.user?.result?.timeline?.timeline?.instructions; | |
| if (!entries) { | |
| console.log("Response:", data); | |
| throw new Error("Could not parse media response"); | |
| } | |
| for (let item of entries) { | |
| if (item.type === "TimelineAddEntries") { | |
| console.log("Raw entries:", item.entries.map(e => e.entryId)); | |
| return item.entries; | |
| } | |
| } | |
| console.log("No TimelineAddEntries found. Instructions:", entries.map(e => e.type)); | |
| return []; | |
| } | |
| async function delete_tweet(tweet_id, retry = 0) { | |
| const response = await fetch("https://x.com/i/api/graphql/VaenaVgh5q5ih7kvyVjgtg/DeleteTweet", { | |
| method: "POST", | |
| headers: { | |
| "accept": "*/*", | |
| "accept-language": buildAcceptLanguageString(), | |
| "authorization": authorization, | |
| "content-type": "application/json", | |
| "x-client-transaction-id": client_tid, | |
| "x-client-uuid": client_uuid, | |
| "x-csrf-token": csrf_token, | |
| "x-twitter-active-user": "yes", | |
| "x-twitter-auth-type": "OAuth2Session", | |
| "x-twitter-client-language": language_code | |
| }, | |
| body: JSON.stringify({ | |
| variables: { tweet_id: tweet_id, dark_request: false }, | |
| queryId: "VaenaVgh5q5ih7kvyVjgtg" | |
| }), | |
| credentials: "include" | |
| }); | |
| if (!response.ok) { | |
| if (response.status === 429) { | |
| console.log("Rate limit on delete. Waiting 1 minute..."); | |
| await sleep(60000); | |
| return delete_tweet(tweet_id, retry + 1); | |
| } | |
| if (retry >= 3) { | |
| console.log(`Failed to delete ${tweet_id} after retries`); | |
| return false; | |
| } | |
| await sleep(5000); | |
| return delete_tweet(tweet_id, retry + 1); | |
| } | |
| return true; | |
| } | |
| // Main execution | |
| (async function() { | |
| console.log("🚀 Starting to delete all media tweets..."); | |
| console.log("User ID:", user_id); | |
| let totalDeleted = 0; | |
| let rounds = 0; | |
| let emptyRounds = 0; | |
| const maxEmptyRounds = 3; // Stop after 3 consecutive empty fetches | |
| while (emptyRounds < maxEmptyRounds) { | |
| rounds++; | |
| console.log(`\n=== Round ${rounds} ===`); | |
| // Always start fresh (no cursor) to get current media | |
| console.log("Fetching media tweets..."); | |
| const entries = await fetch_media(null); | |
| // Find tweet IDs | |
| let tweetIds = []; | |
| for (const entry of entries) { | |
| if (entry.entryId.startsWith("tweet-")) { | |
| tweetIds.push(entry.entryId.replace("tweet-", "")); | |
| } else if (entry.entryId.startsWith("profile-grid-")) { | |
| const items = entry.content?.items || []; | |
| console.log(`Found ${items.length} items in profile-grid`); | |
| for (const item of items) { | |
| const itemId = item.item?.itemContent?.tweet_results?.result?.rest_id | |
| || item.item?.itemContent?.tweet_results?.result?.tweet?.rest_id | |
| || item.item?.itemContent?.tweet_results?.result?.legacy?.id_str; | |
| if (itemId) { | |
| tweetIds.push(itemId); | |
| } | |
| } | |
| } | |
| } | |
| console.log(`Found ${tweetIds.length} media tweets to delete`); | |
| if (tweetIds.length === 0) { | |
| emptyRounds++; | |
| console.log(`No media found (empty round ${emptyRounds}/${maxEmptyRounds})`); | |
| await sleep(3000); | |
| continue; | |
| } | |
| emptyRounds = 0; // Reset empty counter when we find tweets | |
| // Delete each tweet | |
| for (let i = 0; i < tweetIds.length; i++) { | |
| const success = await delete_tweet(tweetIds[i]); | |
| if (success) { | |
| totalDeleted++; | |
| console.log(`Deleted ${totalDeleted}: ${tweetIds[i]}`); | |
| } else { | |
| console.log(`Failed to delete: ${tweetIds[i]}`); | |
| } | |
| await sleep(150); | |
| } | |
| console.log(`Round ${rounds} complete. Total deleted so far: ${totalDeleted}`); | |
| await sleep(2000); | |
| } | |
| console.log(`\n✅ ALL DONE! Deleted ${totalDeleted} media tweets in ${rounds} rounds.`); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment