We've faced datasets with 100,000 points that paralyzed the browser. Here's how we solve such problems with Chart.js, D3.js, and Recharts. Our team has 5+ years of experience and over 50 visualization projects for e-commerce, analytics, and IoT. We use current versions: React 18, TypeScript, D3.js v7, Chart.js 4. We guarantee performance (LCP < 2.5 s) and responsiveness on all devices. We leverage GPU acceleration via Canvas and Web Workers for background data processing.
Development of Interactive Charts
Interactive charts turn raw data into clear insights. Users can zoom into time series, filter categories, and see tooltips with details. This increases engagement by 40% and reduces support load. A pie chart helps quickly assess sales share by category, while a line chart shows revenue trends over time.
Problems We Solve
Slow loading with large datasets. Tens of thousands of data points can paralyze the browser. We use server-side aggregation (PostgreSQL, Redis) and client-side sampling (e.g., downsampling) with virtualized rendering to maintain 60 FPS.
Non-standard visualizations. Standard libraries don't handle user activity heatmaps or force‑directed graphs. That's where D3.js comes in, offering full control over SVG. the official documentation is a powerful library for custom visualizations.
Integration with React. Pure D3.js conflicts with the virtual DOM. Recharts solves this by providing declarative components. But for custom needs, we wrap D3.js in a useEffect hook while respecting reactivity rules and employing memoization via useMemo and useCallback to reduce unnecessary re-renders, leveraging React's reconciliation algorithm for efficient updates.
Insufficient real‑time performance. For streaming data we use WebSockets and incremental updates with requestAnimationFrame for smooth transitions.
Choosing the Right Chart Library
| Tool |
Best For |
Complexity |
Performance |
| Chart.js |
Standard charts (line, bar, pie), quick start |
Low |
Medium (up to 10k points) |
| Recharts |
React apps, declarative code |
Medium |
Good (up to 50k points with virtualization) |
| D3.js |
Custom visualizations (heatmap, treemap, sankey) |
High |
High (any volume with manual optimization) |
Chart.js is 2x easier to set up than D3.js, but D3.js offers 5x more flexibility for non‑standard solutions. Choosing the right library can save up to 40% in development time.
Handling Large Data Volumes
When data exceeds 50,000 points, standard rendering slows down. The answer is server‑side aggregation with time grouping (SQL functions DATE_TRUNC or window functions). On the client we apply downsampling: keep key points, smooth noise. In D3.js, use Canvas instead of SVG to render millions of points, leveraging Web Workers for data processing. Canvas rendering is 5x more efficient than SVG for large datasets. Using server-side aggregation can be up to 10x faster than client-only processing. According to official documentation, Canvas can render over 100,000 points at 60 FPS.
Animating Charts with Performance in Mind
Animation should be purposeful: data appearance, smooth state transitions. In Recharts, use the animationDuration attribute on components. In D3.js, use .transition().duration(). To avoid jitter, animate only changing elements, not the entire canvas. For streaming data, use key props in React to minimize re‑rendering. Employ debounced resize handlers to prevent layout thrashing.
How We Do It: Practical Case
Recently we built a dashboard for an online store showing daily revenue and orders. The client wanted daily statistics with period selection. Stack: React 18, TypeScript, Recharts for charts, Nest.js for API, PostgreSQL with DATE_TRUNC aggregation. To avoid N+1 queries we implemented the Repository pattern and a single endpoint with grouping.
API request:
Route::get('/api/analytics/revenue', function (Request $request) {
return DB::table('orders')
->selectRaw("DATE_TRUNC('day', created_at) as date, SUM(total) as revenue, COUNT(*) as orders")
->where('status', 'completed')
->whereBetween('created_at', [$request->date('from'), $request->date('to')])
->groupByRaw("DATE_TRUNC('day', created_at)")
->orderBy('date')
->get();
});
On the frontend we used useMemo and useCallback to optimize rendering. Charts are wrapped in Suspense with lazy loading.
Optimization technical details
To reduce bundle size we used dynamic imports for charts. That way Recharts isn't loaded until the dashboard block appears. This cut the initial bundle by 20%.
Process
- Analytics: study data, interactivity requirements, target audience.
- Design: choose stack, design components and API.
- Implementation: write code with code review and automated tests.
- Testing: verify with real data, performance (LCP < 2.5 s).
- Deployment: set up CI/CD, CDN, caching.
What's Included
- Source code with comments and documentation.
- Integration with your system (API, CMS).
- Responsive layout for desktop and mobile.
- Team training (1–2 hour webinar).
- 30-day warranty on bugs.
Estimated Timeline and Cost
| Visualization Type |
Timeline |
Typical Cost |
| Standard dashboard (3–5 charts) |
2–3 days |
$500–$1,500 |
| Custom D3.js visualization |
3–5 days |
$1,500–$4,000 |
Cost is calculated individually—depends on complexity and data volume. Our solutions typically save clients $2,000 to $5,000 per project compared to building from scratch.
Typical Mistakes and How to Avoid Them
- Wrong library choice. Don't pick D3.js for simple charts—you'll waste time. Use the table above.
- Lack of responsiveness. Always test on mobile. Use
<ResponsiveContainer>.
- Ignoring performance. For 10k+ points, use aggregation and virtualization (e.g., react-virtualized).
- Unnecessary animation. Animation should help, not distract. Smooth appearance and tooltip are enough.
-
Not optimizing bundle size. Use dynamic imports and code splitting.
Contact us — we'll help you find the best solution for your data. Get a consultation. Order dashboard development.
Setup Web Analytics: GA4, GTM, Yandex.Metrica, and Amplitude
We often see: conversion rate 1.2%, traffic grows, but conversion stays flat. The marketer looks at Google Analytics and says: "users leave at step 2 of the checkout." The developer opens the same step — no errors, Sentry is silent. So it's not a JS bug, but a UX issue or skewed data from analytics. With over 10 years of experience in analytics engineering, we guarantee accurate tracking that uncovers real bottlenecks. Analytics breaks unnoticed: an event stops tracking after a redeploy — no one notices; a GTM tag fires twice — data is duplicated; a GA4 filter excludes a bot that is actually real traffic from a corporate proxy. An audit of your current tags will find the cause within a week.
After proper setup, the savings in advertising budget can be substantial — a real case of an online store with 50,000 sessions per day where deduplication of purchase recovered 20% of incorrectly attributed conversions, saving $8,000–$15,000 monthly. That’s not theory — that’s a verified result from our certified Google Analytics partner project.
Why do GA4 events duplicate and how to fix it?
Universal Analytics is gone, replaced by GA4's event-based model. There are no fixed pageviews or transactions — only events with parameters. This is more flexible but requires proper event design. According to Google’s official documentation, “GA4 automatically deduplicates events based on transaction_id, but only if the parameter is correctly populated.” Many implementations miss this.
Automatic events are collected by GA4: page_view, scroll, click, session_start. Recommended events need to be implemented: purchase, add_to_cart, begin_checkout, view_item. Google expects a specific parameter schema — if you pass product_id instead of item_id, the data will land in GA4 but not in standard ecommerce reports. Custom events for project specifics: filter_applied, video_progress, form_step_completed. Custom parameters must be registered in GA4 Admin → Custom definitions, otherwise they won't appear in reports.
A common mistake is the purchase event being duplicated. Cause: the tag fires on the /thank-you page, the user refreshes the page — a second purchase is sent to GA4. Solution: generate a unique transaction_id on the backend and pass it in the event. In our experience, 80% of e-commerce stores have this issue. GA4 deduplicates based on it (in theory — verify with DebugView). Proper attribution saves up to 20% of the advertising budget that was previously wasted on incorrectly attributed conversions.
How to set up the data layer to avoid data loss?
GTM is a tool for managing tags without code deployment. But "no code" doesn't mean "no architecture." The data layer is the foundation. We pass data from the application to GTM via dataLayer.push(). Structure: event + contextual data. For e-commerce: before opening a product page — push with product data. GTM tag reads from the data layer, not from the DOM.
window.dataLayer = window.dataLayer || [];
dataLayer.push({
event: 'view_item',
ecommerce: {
items: [{
item_id: 'SKU-12345',
item_name: 'Product name',
price: 1990.00,
currency: 'USD'
}]
}
});
Bad practice: GTM tag parses the DOM — looks for the price in span.price, the name in h1. This breaks with any layout change. Good practice: always use the data layer. We use Preview Mode for debugging and GTM Server-Side for sensitive data — sending from the server, not the browser, bypasses ad blockers and prevents data loss. A properly implemented data layer reduces tracking errors by 95%.
How does Yandex.Metrica complement web analytics?
For a Russian audience, Metrica is a must — especially Webvisor. Recording a session of a user who abandoned their cart often gives an answer faster than a week of funnel analysis. Goals in Metrica: event-based (via ym(COUNTER_ID, 'reachGoal', 'GOAL_NAME')) or automatic (button click, page visit). Integration with CRM via Metrica Plus — passing offline conversions. Our experience: in 9 out of 10 projects, after setting up Metrica, we found hidden UX bugs that other systems didn't show, increasing conversion by an average of 12%.
What does product analytics give in Amplitude?
Amplitude is a product tool, unlike marketing-oriented GA4 and Metrica. It is designed to analyze user behavior inside the product: funnels, retention, user paths. Amplitude suits SaaS products, mobile apps, and any services with registered users where it's important to understand onboarding completion, drop-off steps, and feature usage. Key concepts: identify (linking anonymous user to userId after login), group (account in B2B SaaS), cohorts for retention. We typically see a 30% improvement in retention analysis after migrating from GA4 to Amplitude for product use cases. Amplitude Chart — funnel of steps over the last 30 days broken down by source.
Monitoring Data Quality
Analytics without monitoring is a black box. We set up:
- GA4 Realtime — check after every deploy that key events are coming in
- Alerting in GA4 — anomaly in the number of
purchase events (sharp drop = something broke)
- GTM Preview in staging before production
- Manual funnel tests once a week — simply go through the buyer journey and verify everything is tracked
What we check after each deploy
- All recommended events present in DebugView
- No duplicates (count
purchase per 100 sessions)
- Data layer structure unchanged after frontend update
What the work includes
| Component |
Description |
| Audit of existing tags |
Check current GTM tags, data layer, duplicates, and errors |
| Event schema design |
Documentation: event list, parameters, triggers |
| GA4 + GTM setup |
Create configuration, tags, custom definitions |
| Yandex.Metrica |
Install counter, create goals, set up Webvisor |
| Amplitude (optional) |
Set up client and server SDK, cohorts |
| QA and monitoring |
Testing in Preview Mode, alerting |
| Training and handover |
Access, instructions for adding new events, console |
Process and timeline
- Audit of existing tags and data (2 days)
- Event schema design (2 days)
- Data layer development and tag setup (3–5 days)
- QA in Preview Mode and staging (2 days)
- Deploy and dashboard setup (1 day)
| Scenario |
Timeline |
| Basic GA4 + GTM setup |
1 week |
| Full e-commerce tracking + Metrica |
2–3 weeks |
| Server-side GTM + Amplitude |
3–5 weeks |
Cost is calculated individually. Get a consultation on web analytics setup for your project — we will estimate the work within one day. Contact us to get started with a free audit of your current tracking.