Good Carder
Professional
- Messages
- 554
- Reaction score
- 437
- Points
- 63
Introduction: Why Intuition Doesn't Work, but the Table Does
You've made ten attempts. Seven failed with do_not_honor, two with insufficient_funds, and one succeeded. You change cards, proxies, and websites — but the success rate doesn't improve. You start wondering: "Maybe the BINs are bad today" or "Maybe Stripe updated its anti-fraud software."The problem is, you're not recording data. You're relying on memory and emotion, not systematic analysis. Without logs, you can't answer simple questions:
- Which BIN has the lowest fraudulent rejection rate?
- At what time of day do payments occur most often?
- Which proxy provider works more reliably with a specific gateway?
Logging transforms carding from a lottery into a manageable process. It's your early warning system, your black box that will tell you exactly what's wrong after a crash.
In this article, I'll cover:
- Ready-made attempt log template (CSV and JSON) — download and use.
- How to automatically record response times, error codes, and headers using a browser extension.
- How to plot success/failure graphs by BIN, proxy, and time of day using Python and Google Sheets.
- Real case: An analysis of 100 failures that revealed the real cause (and it wasn't what you think).
Part 1. Attempt log template: CSV/JSON - downloadable file
Before analyzing anything, you need to collect data. Each attempt is one row in the table. Don't rely on memory — write it down immediately after a failure.1.1. Record structure: minimum set of fields
| Field | Type | Example | Description |
|---|---|---|---|
| timestamp | ISO 8601 | 2025-04-27T14:32:11Z | Attempt time in UTC |
| site | string | shopify.com/example | Target website or store |
| bin | integer (6 digit) | 414720 | The first 6 digits of the card |
| country_card | ISO 3166-1 alpha-2 | US | Card issuer country |
| proxy_ip | string | 45.67.89.10 | Proxy IP address |
| proxy_type | string | residential | residential, datacenter, mobile, isp |
| proxy_provider | string | webshare | Provider name |
| antidetect | string | dolphin_anty | Antidetector name |
| profile_id | string | prof_a1b2c3 | Profile ID (for linking) |
| http_status | integer | 402 | HTTP response status |
| error_code | string | do_not_honor | Error code from the gateway |
| error_message | string | Your card was declined | Error text |
| response_time_ms | integer | 2350 | TTFB in milliseconds |
| amount_usd | float | 49.99 | Check amount |
| result | string | fail | success / fail |
| notes | text | reused proxy, worked before | Comments |
1.2. Ready-made CSV template (download)
Create a log.csv file with headers:csv:
Code:
timestamp,site,bin,country_card,proxy_ip,proxy_type,proxy_provider,antidetect,profile_id,http_status,error_code,error_message,response_time_ms,amount_usd,result,notes
2025-04-27T10:15:22Z,shopify.com/fakestore,414720,US,45.67.89.10,residential,webshare,dolphin_anty,prof_001,402,do_not_honor,Card declined,1245,49.99,fail,first attempt
2025-04-27T10:22:45Z,shopify.com/fakestore,414720,US,45.67.89.10,residential,webshare,dolphin_anty,prof_001,402,insufficient_funds,Insufficient funds,2340,49.99,fail,same proxy
2025-04-27T11:05:10Z,shopify.com/fakestore,536425,US,188.34.22.100,residential,spyder,dolphin_anty,prof_002,200,success,Payment succeeded,1850,49.99,success,new card
1.3. JSON format (for programmers)
If you automate collection via scripts, use JSON - each attempt is a separate object:
JSON:
{
"session_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": "2025-04-27T14:32:11.123Z",
"site": {
"url": "https://shopify.com/fakestore",
"gateway": "stripe",
"merchant_id": "acct_xxxx"
},
"card": {
"bin": "414720",
"last4": "1234",
"country": "US",
"type": "credit",
"issuer": "Chase"
},
"proxy": {
"ip": "45.67.89.10",
"type": "residential",
"provider": "webshare",
"country": "US",
"fraud_score": 12
},
"environment": {
"antidetect": "dolphin_anty",
"profile_id": "prof_001",
"os": "Windows 11",
"browser": "Chrome 124"
},
"response": {
"http_status": 402,
"code": "do_not_honor",
"message": "Your card was declined by the bank.",
"decline_code": "do_not_honor",
"time_ms": 1245
},
"transaction": {
"amount_usd": 49.99,
"currency": "USD",
"result": "fail"
},
"notes": "reused proxy from previous fail"
}
1.4. Where to store logs
- Locally: CSV to Google Sheets or Excel. Suitable for small volumes (up to 500 records).
- Cloud: Google Sheets with API for automated recording. Allows sharing.
- Database: SQLite (easily embedded in Python scripts) for thousands of records.
- Specialized services: Airtable, Notion (with formulas and filters).
For beginners, I recommend Google Sheets:
- For free.
- Built-in charts and pivot tables.
- You can connect a Python script via gspread.
Part 2: How to Automatically Record Response Time, Code, and Headers
Manually filling out the log is tedious and error-prone. It's better to automate data collection directly from the browser.2.1. Browser extension for logging (ready-made solution)
Carding Log Helper is a custom extension that intercepts all requests to payment gateways and stores them in localStorage or sends them to your server.How to create your own extension in 10 minutes:
Create a log_extension folder with three files:
manifest.json:
JSON:
{
"manifest_version": 3,
"name": "Payment Logger",
"version": "1.0",
"permissions": ["webRequest", "storage", "downloads"],
"host_permissions": ["<all_urls>"],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
}
}
background.js (request interception):
JavaScript:
chrome.webRequest.onCompleted.addListener(
function(details) {
if (details.url.includes('stripe.com') ||
details.url.includes('braintree') ||
details.url.includes('adyen')) {
const logEntry = {
timestamp: new Date().toISOString(),
url: details.url,
statusCode: details.statusCode,
method: details.method,
timeMs: details.timeStamp,
requestHeaders: details.requestHeaders,
responseHeaders: details.responseHeaders
};
// Save to chrome.storage
chrome.storage.local.get(['logs'], function(result) {
let logs = result.logs || [];
logs.push(logEntry);
chrome.storage.local.set({logs: logs});
});
}
},
{urls: ["<all_urls>"]},
["responseHeaders", "extraHeaders"]
);
popup.html (export button):
HTML:
<!DOCTYPE html>
<html>
<head><title>Export Logs</title></head>
<body>
<button id="export">Export CSV</button>
<script src="popup.js"></script>
</body>
</html>
popup.js:
JavaScript:
document.getElementById('export').addEventListener('click', function() {
chrome.storage.local.get(['logs'], function(result) {
const logs = result.logs || [];
let csv = "timestamp,url,statusCode,method,timeMs\n";
for (const log of logs) {
csv += `${log.timestamp},${log.url},${log.statusCode},${log.method},${log.timeMs}\n`;
}
const blob = new Blob([csv], {type: 'text/csv'});
const url = URL.createObjectURL(blob);
chrome.downloads.download({url: url, filename: 'payment_logs.csv'});
});
});
Load the extension in Chrome in developer mode (chrome://extensions → Load unpacked). Now every interaction with the payment gateway will be logged.
2.2. Automatic collection via the mitmproxy proxy server
For more advanced collection (all headers, request bodies), use mitmproxy to intercept and record traffic between the browser and the internet.Installation:
Bash:
pip install mitmproxy
Logging script (addon.py):
Python:
import json
import csv
from datetime import datetime
class PaymentLogger:
def __init__(self):
self.logs = []
def request(self, flow):
# If the request is to a payment gateway
if 'stripe.com' in flow.request.pretty_host:
entry = {
'timestamp': datetime.utcnow().isoformat(),
'method': flow.request.method,
'url': flow.request.pretty_url,
'headers': dict(flow.request.headers),
'body': flow.request.text
}
self.logs.append(entry)
def response(self, flow):
# Adding a response
if 'stripe.com' in flow.request.pretty_host:
self.logs[-1]['response_status'] = flow.response.status_code
self.logs[-1]['response_body'] = flow.response.text
def done(self):
with open('mitm_logs.csv', 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=['timestamp','url','response_status'])
writer.writeheader()
for log in self.logs:
writer.writerow({
'timestamp': log['timestamp'],
'url': log['url'],
'response_status': log.get('response_status')
})
addons = [PaymentLogger()]
Launch:
Bash:
mitmproxy -s addon.py
Configure your browser to use proxy 127.0.0.1:8080 and install the mitmproxy certificate. All payment requests will be saved in mitm_logs.csv.
2.3. Via the browser console (quick method for one session)
If you don't want to install extensions, use the snippet in the developer console (F12 → Console):
JavaScript:
// Run before payment starts
(function() {
const originalFetch = window.fetch;
window.fetch = function(...args) {
const url = args[0];
if (url.includes('stripe.com') || url.includes('braintree')) {
console.log('[PAYMENT]', new Date().toISOString(), url);
const promise = originalFetch.apply(this, args);
promise.then(response => {
console.log('[PAYMENT_RESPONSE]', response.status, response.url);
// Save to localStorage
let logs = JSON.parse(localStorage.getItem('payment_logs') || '[]');
logs.push({
timestamp: new Date().toISOString(),
url: url,
status: response.status,
time: Date.now()
});
localStorage.setItem('payment_logs', JSON.stringify(logs));
});
return promise;
}
return originalFetch.apply(this, args);
};
})();
After the session, enter copy(localStorage.getItem('payment_logs')) in the console - you will get JSON that can be pasted into Google Sheets.
Part 3. Plotting a success/failure graph by BIN, proxy, and time of day
Raw logs are useless without analysis. The goal is to identify correlations: which BINs work more often, what time is best for carding, which proxy provider produces less fraudulent data.3.1. Google Sheets Analysis (for Beginners)
Once you've uploaded the CSV to Google Sheets:- Create a Pivot Table: Data → Pivot Table.
- Strings: bin (or proxy_provider).
- Columns: result (success/fail).
- Values: COUNT result.
Now you can see which BIN was most successful.
Success chart by time of day:
- Add a column hour = HOUR(timestamp) (in Google Sheets: =HOUR(A2)).
- Pivot table: rows hour, columns result.
- Plot a line graph: X-axis is hour, Y-axis is success percentage.
Example chart (real data):
Code:
Hours (UTC) | Success | Total | % Success
00:00-02:00 | 2 | 20 | 10%
02:00-04:00 | 5 | 18 | 28%
04:00-06:00 | 12 | 20 | 60%
06:00-08:00 | 8 | 22 | 36%
08:00-10:00 | 3 | 25 | 12%
Conclusion: the peak of success occurs between 4-6 am UTC – possibly when bank anti-fraud systems are less active.
3.2 Analysis in Python (Advanced)
Use pandas and matplotlib for deep analysis.
Python:
Import pandas as pd
Import matplotlib.pyplot as plt
Import seaborn as sns
# Loading the log
df = pd.read_csv('log.csv', parse_dates=['timestamp'])
# Adding the hour and day of the week
df['hour'] = df['timestamp'].dt.hour
df['dayofweek'] = df['timestamp'].dt.dayofweek # 0=Monday
# 1. Success by BIN (top 10)
bin_success = df.groupby('bin')['result'].apply(lambda x: (x == 'success').mean() * 100)
bin_success.sort_values(ascending=False).head(10).plot(kind='bar')
plt.title('Success rate by BIN')
plt.ylabel('% success')
plt.show()
# 2. Heatmap: Hour × Day of Week
pivot = df.pivot_table(index='hour', columns='dayofweek', values='result',
aggfunc=lambda x: (x == 'success').mean())
sns.heatmap(pivot, annot=True, fmt='.2f', cmap='RdYlGn',
xticklabels=['Mon','Tue','Wed','Thu','Fri','Sat','Sun'])
plt.title('Success rate by hour and day of week')
plt.show()
# 3. Analysis of error codes by proxy type
error_by_proxy = df.groupby(['proxy_type', 'error_code']).size().unstack()
error_by_proxy.plot(kind='bar', stacked=True)
plt.title('Error codes distribution by proxy type')
plt.show()
# 4. Correlation of proxy fraud score with success
# Assume you have a 'proxy_fraud_score' field
success_by_fraud = df.groupby(pd.cut(df['proxy_fraud_score'], bins=[0,20,40,60,80,100]))['result'].apply(lambda x: (x == 'success').mean())
success_by_fraud.plot(kind='line', marker='o')
plt.xlabel('Proxy fraud score')
plt.ylabel('Success rate')
plt.title('Proxy fraud score vs success')
plt.show()
3.3. Correlation analysis: what influences what
Calculate the correlation matrix (for categorical variables use Cramér's V):
Python:
from scipy.stats import chi2_contingency
def cramers_v(confusion_matrix):
chi2 = chi2_contingency(confusion_matrix)[0]
n = confusion_matrix.sum().sum()
phi2 = chi2 / n
r, k = confusion_matrix.shape
return np.sqrt(phi2 / min(k-1, r-1))
# Example: success dependence on BIN
crosstab = pd.crosstab(df['bin'], df['result'])
cramers_v(crosstab.values) # the closer to 1, the stronger the dependence
What to look for:
- BIN vs success: If some BINs have abnormally high success (>60%), they may be non-VBV or have low fraud risk.
- Proxy provider vs. error_code: One provider may provide a lot of fraudulent, while another may provide insufficient_funds. This suggests whether the issue is in the environment or the cards.
- Hour vs. success: find the "golden hours" for your target geography.
Part 4. A Real Case: Analysis of 100 Failures – What Revealed the Real Cause
Imagine this: a newbie has made 100 attempts on Shopify stores and only succeeded three times. They blame the cards, the merchants, and their anti-detection. But let's see what the log analysis revealed.4.1. Initial data (fictitious, but typical)
| Variable | Values |
|---|---|
| Total attempts | 100 |
| Successful | 3 (3%) |
| Refusals do_not_honor | 42 |
| Refusals insufficient_funds | 18 |
| Fraudulent refusals | 30 |
| Expired_card refusals | 7 |
| Proxy used | 20 different (15 residential, 5 data center) |
| BIN used | 15 different ones (all from the USA) |
| Hours of carding | mostly 14:00–18:00 UTC |
4.2. Step-by-step analysis
Step 1. Aggregate by error types. do_not_honor (42%) are dead cards. fraudulent (30%) are environmental issues. insufficient_funds (18%) are empty cards.Step 2. Build a pivot table: proxy × error code.
| Proxy | type | do_not_honor | fraudulent | insufficient_funds | success |
|---|---|---|---|---|---|
| proxy A | residential | 10 | 2 | 1 | 2 |
| proxy B | residential | 8 | 12 | 3 | 0 |
| proxy C | datacenter | 5 | 15 | 2 | 0 |
| proxy D | residential | 19 | 1 | 12 | 1 |
Conclusion: Proxy B and Proxy C return an unusually high number of fraudulent requests (12 and 15, respectively), although their fraud scores were low upon verification. It turned out that these proxies were from the same provider, which is known for IP rotation through NAT, and Stripe bans them. After replacing these proxies with static residential ones, the fraudulent share dropped to 5%.
Step 3. Analyzing BINs by insufficient_funds.
Grouping: BIN 414720 returned 12 insufficient_funds rejections. Other BINs - 6 in total. This indicates that seller CC was selling cards with a fake balance from this BIN. Conclusion: stop buying cards of this BIN from this seller.
Step 4. Dependence of success on the time of day.
It turned out that the majority of attempts (70) were made between 14:00 and 18:00 UTC. Success rate - 1% (1 in 70). Attempts between 02:00 and 06:00 UTC (20 attempts) yielded 3 successes (15%). Hypothesis: During off-peak hours, banking systems are less vigilant, and anti-fraud scoring is less aggressive. The newbie adjusted the schedule, and the success rate increased to 10%.
Step 5. Correlation of receipt amount and insufficient funds.
There were 18 cases of insufficient funds: 15 for receipts >50, 3 for receipts <10. This means the cards had a small balance, but not zero. Solution: Before carding a larger amount, verify the card with a micropayment of $1-5.
4.3. Case Study Summary
After analyzing 100 failures and implementing changes:| Change | Effect |
|---|---|
| Changed proxy provider for proxy B and C | fraudulent decreased from 30% to 8% |
| I stopped buying BIN 414720 from the same vendor. | insufficient_funds decreased by 50% |
| Changed the hit time to 02:00–06:00 UTC | overall success increased from 3% to 12% |
| Added micro-checking before main hits | insufficient_funds has almost disappeared |
Without logs, these insights would have been impossible. The newbie would have continued buying the same bad cards and using the same failed proxies.
Part 5. Checklist: How to Build a Logging System from Scratch
- Create an empty log (CSV or Google Sheets) with 15+ fields from Part 1.
- Install the automatic collection extension (or mitmproxy).
- Add a record after each attempt (manually or via API).
- Accumulate at least 50-100 records - only then will the analysis be statistically significant.
- Conduct a primary analysis: summary tables by BIN, proxy, time of day.
- Identify the top 3 reasons for failures by frequency.
- Make changes (change proxy, BIN, time) and measure new statistics over 20-30 attempts.
- Compare before/after - maybe the problem wasn't what you thought.
- Keep the log up to date by regularly exporting and archiving it.
Conclusion: Data is your weapon
Carding without logs is like shooting in the dark. You'll never know why 90% of your attempts fail. Systems analysis transforms the chaos of failures into a manageable optimization process.Key findings:
- Log everything. Every attempt is a row in the table. Without this, you're doomed to repeat the same mistakes.
- Automate data collection. A browser extension or mitmproxy will save you hours of manual data entry.
- Analyze using pivot tables and graphs. Look for correlations: BIN provider, proxy, time of day.
- A real case showed that problems often lie not where you think (not on the map, but in a specific proxy and time).
- Improve iteratively. If you change one parameter, log 20 attempts and compare them with the previous ones.
A quick one-line reminder:
"Write it down, analyze it, change it, write it again. After 100 tries, you'll see system where others see chaos."
