Comparison
CargoSharks and the spreadsheet
The real incumbent, and the one alternative here we can be blunt about — a spreadsheet has no vendor to misrepresent. It is also better than most software at several things, which is why it is still winning.
01 — Three moments
It does not break gradually. It breaks at three specific moments
A spreadsheet has no vendor, no roadmap and nothing to misrepresent, so this is the one page here that can be direct. It is also better than most software at several things, which is why it is still winning. What follows is not an argument that it is bad — it is the three moments at which it stops being the cheaper option, each one a thing that has already happened to somebody reading this.
01
The second person joins
Two people quoting from one workbook eventually send two prices for one lane, and the version that goes out is whichever one the person quoting had open. Nobody notices until the customer puts them side by side.
On a file: A rate card carries a lane, a mode, a carrier and validity dates, and the database itself will not accept two that cover the same route at the same time.
02
A container sits past its free days
Starting the counter is somebody’s job and it is nobody’s job. It surfaces six weeks later on a supplier invoice, at which point the question has stopped being how much and become who was supposed to be watching.
On a file: The milestone that ends free time starts the clock, and the charge line is written against the job on the day rather than found on a statement.
03
Somebody asks who changed it
A spreadsheet has one truth and no history. When a date moved, who moved it and what it said before are not hard questions — they are questions with no answer at all, which is a different and worse thing.
On a file: Nothing is deleted. Every change is stamped with who made it and when, and a superseded row is marked superseded and stays where it was.
One container: five free days, then KWD 28.000 a day
02 — The case against us
Keep the spreadsheet if
This section comes before the next one on purpose. A comparison page that cannot name a reader who should buy the other product is not a comparison.
- You move a handful of shipments a month. Below some volume the overhead of any system is larger than the problem it solves, and anyone who tells you otherwise is selling.
- One person does the whole job end to end and it is all in their head. The thing a file replaces is a handover, and you do not have one.
- Nothing has ever surfaced weeks late on a supplier invoice. If that is genuinely true, the case below does not apply to you.
03 — The case for us
The three places it breaks
Every point below is a mechanism you can check in the demo or in the source, rather than a promise.
- A clock nobody starts. Free time runs out, the counter is somebody’s job and it is nobody’s job, and it surfaces weeks later on a supplier invoice. A file that knows the discharge milestone starts the clock itself and writes the charge line as it runs.
- Two people, one rate. Rate cards in a shared workbook overlap, and the version that goes out is whichever one the person quoting had open. In the database, two cards cannot cover one lane at one time.
- Nobody can say who changed it. A spreadsheet has one truth and no history, so the question of when a date moved and who moved it has no answer at all — where a file with 80 audit triggers has a boring one.
| The claim | Figure | How you check it |
|---|---|---|
| Transport modes | 5 | Sea FCL, sea LCL, air, road, rail and courier appear in the mode selector on any enquiry in the demo. |
| Row-level security policies | 197 | select count(*) from pg_policies where schemaname = 'public' — against any deployment, ours or yours. The policies are written by loops over the table registry, so a grep of the migration text counts the loops rather than the policies; pnpm test:db fails the build if any table lacks one. |
| Audit triggers | 80 | select count(*) from pg_trigger where tgname like '%\_audit' and not tgisinternal — attached by a loop rather than by a list, so a table added in a later migration is covered without anybody remembering to add it. |
| Interface strings, English and Arabic | 2,727 | pnpm lint runs check-messages.mjs, which fails the build if a key exists in one catalogue and not the other. |
| Decimal places on every dinar | 3 | Open any invoice in the demo. A system built for dollars and adapted shows two. |
| Minutes to check all of the above | ~10 | No sign-up and no call. That is the claim this whole page rests on. |
On the screen
The screen the argument above is made on

04 — The questions
Ask both of us these, and compare the answers
Our answers are already written, and beside each one is what a good answer sounds like from any vendor — including us. Somebody who takes this list to another vendor’s call and gets a better answer than ours should buy from them, which is what makes it worth publishing.
| The question | Our answer | What a good answer sounds like |
|---|---|---|
| Is the Arabic a translation layer, or is it the same build? | The same build. Right-to-left is in the layout rather than added on top of it, and `pnpm lint` fails if a string exists in one language and not the other. Open the demo, press the language switch, and look at a delivery order. | A good answer names a mechanism — a parity check that fails a build, one catalogue rather than two, right-to-left in the layout. A weak one is “yes, we support Arabic” plus a screenshot. Ask to see a printed delivery order rather than a screen: that is where an added-on language shows first. |
| How many decimal places does an invoice in Kuwaiti dinars carry? | Three, everywhere, because the dinar has three. This is the single fastest way to find out whether a system was built for dollars and adapted. | “Three” should come back instantly and without conditions. Hesitation, or “it is configurable”, usually means money is a floating-point number somewhere and the decimals are a display setting — which is fine until a rounding difference lands on a reconciliation. |
| Whose database is it, and can I have a copy of my data on a Tuesday afternoon without asking? | PostgreSQL, and yes. The separation between customers is enforced by the database itself rather than by our application, which is also what makes the answer to the first half of that question boring. | Listen for a named engine and an export you can trigger yourself. “We can arrange an extract” is a different answer from “here is the button”, and the difference is what leaving costs you in three years. |
| What does it cost when volume doubles? | Ask every vendor this and ask for the answer in writing. Per-shipment and per-transaction pricing is normal in this category and is not a trick — but it is a different shape of bill from a flat one, and the difference shows up in year two rather than at signature. | Any pricing shape is defensible; a refusal to put the shape in writing is not. Ask for the figure at twice and five times today’s volume, in the contract rather than on a call — and ask us the same way. |
| Can I see it working, today, without a call? | Yes — demo.cargosharks.com, no sign-up. We think this question separates vendors more reliably than any feature question, which is why it is last. | The answer is yes or no, and both are legitimate. A demo that needs a discovery call first is a sales process rather than a fault — but it is also a reliable measure of how long a pilot will take to start. |
What you will not find on this page
A tick-and-cross grid. We know our product properly and theirs from the outside, and a grid written by one side is not a comparison — it is an argument with a table around it. Worse, it goes stale silently: every entry starts decaying the day it is published, and the person it misleads is your prospect while the person who looks foolish is you.
Ask us directly at [email protected]. You will get a written answer that cites what each vendor publishes itself, and where we do not know, you will get “we do not know”.