Amazon no longer offers order history reports. This free script saves every order (date, order number, total, status and each product) to a CSV you can open in Excel or Google Sheets.
Works on every Amazon store: .com, .co.uk, .ca, .de, .fr, .es, .it, .com.au… Open Your Orders on your own store.
// Responsive Muse · Amazon Order History Exporter · v1.1 · 2026-10-22
// Exports your Amazon orders to CSV, one row per product: order date, order number, order total,
// status, product title, ASIN and links. Works on any Amazon store (.com, .co.uk, .de, .es…).
// Runs only on amazon.*/your-orders (Returns & Orders). To read every page of results it opens
// them in a hidden frame of the same Amazon site, like clicking "Next" yourself. It never sends
// anything anywhere and never reads cookies, passwords or tokens.
(async () => {
const TOOL = 'Export Amazon orders';
const YEARS = 'all'; // 'all', one year like '2025', or several like '2024,2025'
const DELAY = 1500; // pause between pages, in milliseconds
if (!/^(www\.|smile\.)?amazon\.[a-z.]+$/.test(location.hostname) ||
!/^\/(your-orders|gp\/css\/order-history|gp\/your-account\/order-history)/.test(location.pathname)) {
alert('Open Returns & Orders first (signed in),\nfor example amazon.com/your-orders/orders');
return;
}
// A small box on the page shows progress and asks before changing anything,
// so you never need to read or edit the console.
const many = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`; // 1 video, 2 videos
const panel = (() => {
const box = document.createElement('div');
box.style.cssText = 'position:fixed;right:16px;bottom:16px;z-index:2147483647;width:340px;max-width:calc(100vw - 32px);' +
'background:#111318;color:#e6e8ee;font:14px/1.5 system-ui,sans-serif;border-radius:12px;padding:16px;' +
'box-shadow:0 8px 30px rgba(0,0,0,.4);text-align:left';
const head = document.createElement('strong');
head.textContent = TOOL;
const msg = document.createElement('p');
msg.style.cssText = 'margin:8px 0 12px;white-space:pre-line';
const row = document.createElement('div');
row.style.cssText = 'display:flex;flex-wrap:wrap;gap:8px;justify-content:flex-end';
box.append(head, msg, row);
document.body.append(box);
const button = (label, primary, onClick) => {
const b = document.createElement('button');
b.textContent = label;
b.style.cssText = 'font:600 14px system-ui,sans-serif;padding:8px 14px;border-radius:8px;cursor:pointer;' +
(primary ? 'background:#0f766e;color:#fff;border:1px solid #0f766e' : 'background:none;color:#e6e8ee;border:1px solid #3a3f4b');
b.onclick = onClick;
row.append(b);
};
return {
text(t) { msg.textContent = t; },
ask(t, yes) {
msg.textContent = t;
row.replaceChildren();
return new Promise(r => {
button('Cancel', false, () => { row.replaceChildren(); r(false); });
button(yes, true, () => { row.replaceChildren(); r(true); });
});
},
stoppable(onStop) { row.replaceChildren(); button('Stop', false, onStop); },
actions(t, list) {
msg.textContent = t;
row.replaceChildren();
list.forEach(([label, primary, run]) => button(label, primary, run));
},
finish(t) { this.actions(t, [['Close', true, () => box.remove()]]); },
close() { box.remove(); },
};
})();
// Offer the result as a downloaded file or as clipboard text (a real click, so it always works)
const deliver = (summary, body, file) => {
const save = () => {
const a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([/\.csv$/.test(file) ? '\ufeff' + body : body], { type: 'text/plain;charset=utf-8' }));
a.download = file;
a.click();
setTimeout(() => URL.revokeObjectURL(a.href), 5000);
panel.text(`${summary}\nSaved as ${file} (check your Downloads).`);
};
const copy = () => navigator.clipboard.writeText(body)
.then(() => panel.text(`${summary}\nCopied. Paste it into a spreadsheet or a note.`))
.catch(() => panel.text(`${summary}\nThe browser blocked the clipboard: use Download instead.`));
panel.actions(summary, [['Close', false, () => panel.close()], ['Copy', false, copy], ['Download', true, save]]);
};
const sleep = ms => new Promise(r => setTimeout(r, ms));
// Years offered by Amazon's own "orders placed in" menu
const offered = [...document.querySelectorAll('select[name="timeFilter"] option, #time-filter option')]
.map(o => o.value).filter(v => /^year-\d{4}$/.test(v)).map(v => v.slice(5));
const years = YEARS === 'all' ? offered : String(YEARS).split(',').map(y => y.trim()).filter(Boolean);
if (!years.length) {
panel.finish('Could not find the year menu. Amazon may have changed its layout: please report it on responsive-muse.com.');
return 0;
}
// Load one results page of Amazon's own order history in a hidden frame and wait for it
const loadPage = path => new Promise(resolve => {
const frame = document.createElement('iframe');
frame.style.cssText = 'position:absolute;left:-9999px;width:1000px;height:800px';
const done = doc => { resolve(doc); setTimeout(() => frame.remove(), 0); };
frame.onload = () => done(frame.contentDocument);
setTimeout(() => done(null), 30000);
frame.src = new URL(path, location.origin).href;
document.body.appendChild(frame);
});
// Read the order cards of one page
const readOrders = doc => [...doc.querySelectorAll('.js-order-card, .order-card')].map(card => {
const text = el => (el?.textContent || '').replace(/\s+/g, ' ').trim();
// Header blocks: "Order placed / <date>", "Total / <amount>", "Ship to / <name>"
const blocks = card.querySelectorAll('.order-header__header-list-item');
const values = [...(blocks.length ? blocks : card.querySelectorAll('.order-header .a-column'))]
.map(b => text(b.querySelectorAll('.a-row')[1] || b.querySelector('.a-size-base')));
const id = text(card.querySelector('.yohtmlc-order-id bdi, .yohtmlc-order-id span[dir="ltr"]'));
// Amazon leaves the status empty on older delivered orders
const status = [...card.querySelectorAll('.delivery-box__primary-text, .yohtmlc-shipment-status-primaryText')]
.map(text).find(Boolean) || '';
const products = new Map();
card.querySelectorAll('a[href*="/dp/"], a[href*="/gp/product/"]').forEach(a => {
const asin = (a.href.match(/\/(?:dp|product)\/([A-Z0-9]{10})/) || [])[1];
if (!asin) return;
const title = text(a) || a.querySelector('img')?.alt || '';
if (!products.has(asin) || (title && !products.get(asin))) products.set(asin, title);
});
return { id, date: values[0] || '', total: values[1] || '', status, products: [...products] };
});
// 1. Every page of every year
let stop = false;
panel.stoppable(() => { stop = true; });
const orders = [];
for (const year of years) {
for (let page = 1; page <= 100 && !stop; page++) {
panel.text(`Reading ${year}, page ${page}… ${orders.length} orders so far`);
const doc = await loadPage(`/your-orders/orders?timeFilter=year-${year}&page=${page}`);
if (!doc) break;
const found = readOrders(doc).filter(o => o.id && !orders.some(x => x.id === o.id));
orders.push(...found);
const nextDisabled = doc.querySelector('.a-pagination .a-last.a-disabled');
const hasNext = doc.querySelector('.a-pagination .a-last a');
if (!found.length || nextDisabled || !hasNext) break;
await sleep(DELAY);
}
if (stop) break;
}
if (!orders.length) {
panel.finish('No orders found for those years. Check the years, or Amazon may have changed its layout.');
return 0;
}
// 2. One row per product, then offer the file
const cell = v => '"' + String(v).replace(/"/g, '""') + '"';
const rows = orders.flatMap(o => (o.products.length ? o.products : [['', '']]).map(([asin, title]) => [
o.date, o.id, o.total, o.status, title, asin, asin ? `${location.origin}/dp/${asin}` : '',
`${location.origin}/gp/your-account/order-details?orderID=${o.id}`,
]));
const body = ['Order date,Order number,Order total,Status,Product,ASIN,Product URL,Order URL',
...rows.map(r => r.map(cell).join(','))].join('\n');
deliver(`${stop ? 'Stopped early. ' : ''}Found ${many(orders.length, 'order')} (${many(rows.length, 'product')}).`, body,
`amazon-orders-${years.join('-')}.csv`);
return orders.length;
})();
Bookmarklet: drag the middle button to your bookmarks bar, open www.amazon.com and click the bookmark. It runs the same script with the options above.
- Sends nothing anywhere. No fetch, XHR or external scripts. The only network activity is www.amazon.com itself loading your list.
- Never touches your login. It doesn't read cookies, passwords, tokens or browser storage.
- Only runs on www.amazon.com. Anywhere else it stops before doing anything.
- Short and readable. 154 commented lines, not minified or obfuscated.
- Shows its progress on the page. A small box tells you what it's doing and offers Download or Copy at the end.
- Same code for everyone. SHA-256 of the default version:
aeb6805b2e4d1a44…
Verify it yourself in 30 seconds
- Read it: every line is above, with comments.
- Search the code for
fetch,XMLHttpRequest,cookie,localStorageoreval. None of them appear. - Open the Network tab before running it: you'll only see requests to www.amazon.com.
How to use it
- Open Your Orders on your Amazon store (for example amazon.co.uk or amazon.de) while signed in.
- Open the console: F12 or Ctrl+Shift+J (Cmd+Option+J on Mac). If Chrome asks, type
allow pastingand press Enter. - Choose the years (“all” by default), copy the script, paste it in the console and press Enter. It reads every page of every year then shows a box: click Download to save one CSV.
Why is there no export button?
Amazon removed its “Order History Reports” tool. The official alternative is a full data request that takes days and arrives as a zip of raw files. This script reads the order pages you can already see, one page at a time, at a gentle pace, and puts them in a single spreadsheet. Handy for expense reports, taxes and budgeting.
FAQ
Doesn't Amazon have an order report?
It used to ("Order History Reports"), but Amazon retired it. The only official option now is a data request that can take days. This script reads the same pages you see under Your Orders.
Why is the status empty on old orders?
Amazon itself leaves the delivery status blank on older delivered orders, so there is nothing to export there. Dates, totals and products are always included.
Is it slow with many orders?
It reads about one page of 10 orders every 2–3 seconds. A few hundred orders take a minute or two. Keep the tab open.
Does it see my card or address?
It only reads the order list: date, number, total, status and products. It doesn't open payment pages.
