Thanks for participating!
Build a multi-channel marketing dashboard that visualizes ad performance data across four platforms: Facebook, Google, Instagram, and LinkedIn. Two API endpoints are available — your job is to consume them, make the data legible, and give users the tools to act on it.
This is intentionally open-ended. The requirements below define the floor — how far above it you go is up to you.
Questions welcome. If anything here is unclear, ask. We'd rather clarify upfront than have you build in the wrong direction.
What You Must Build
-
Dashboard page. A single overview page with summary widgets for all
supported platforms. Each widget should give the user a quick read on key performance
indicators and link through to the appropriate detail page. Use
GET /v1/metrics-summaryfor this page (fixed 30-day rolling window, no date parameters needed). - One page per network. Detail pages for Meta (Facebook + Instagram), Google, and LinkedIn. These pages should go deeper than the dashboard — surface platform-specific metrics, show trends over time, and make the data explorable.
- Charts. Each network page must include at least one chart visualizing data over time. If you include multiple charts, decide the best way to present them (tabs, toggle, layered, etc.).
- Date range and comparison. The detail pages must include a date range picker. Default: 14 days. Minimum: 7 days. Maximum: 30 days. The comparison period (equal-length window immediately before the selected range) is computed automatically by the backend — no second date picker needed. Show a delta on each metric indicating whether the change is favorable or unfavorable.
- CSV export. Users must be able to export the relevant data as a CSV file. The export should reflect the current view and include enough context to be useful on its own.
- Navigation. Users must be able to move between the dashboard and each network page without a full page reload. Use react-router-dom for client-side routing.
- Loading and error states. Every data fetch must have a visible loading state and a visible error state. The user should never see a blank screen with no explanation.
- Custom hooks. Data fetching logic must live in custom hooks, not inline in components. Components should stay focused on rendering; data logic should be reusable and independently testable.
Tech Stack
The following are required:
| Layer | Requirement |
|---|---|
| Language | TypeScript |
| Framework | React |
| Styling | styled-components |
| Routing | react-router-dom |
| Charts | A chart library — we suggest react-google-charts, but any equivalent is fine |
| CSV export | A CSV parser library (e.g. papaparse) — don't hand-roll string concatenation |
Everything else is your call. If you want to add a state management library, a component library, or additional utilities, go for it — just be ready to explain why.
API Reference
Base URL: https://eulerity-hackathon.appspot.com
The Vite dev server proxies /v1/* to this base URL, so during local
development you can call endpoints with relative paths (e.g.
/v1/metrics-summary).
GET /v1/metrics-summary
Returns all four platforms in a single payload for the dashboard overview. The window is always today minus 29 days (current) and the 30 days before that (previous). No parameters — the backend computes everything.
Sample: https://eulerity-hackathon.appspot.com/v1/metrics-summary
GET /v1/metrics-insights?network=<name>&startDate=<date>&endDate=<date>
Returns full daily metrics for a single network, including rate fields and platform-specific engagement. Use this for per-network detail pages.
| Parameter | Required | Values |
|---|---|---|
network | Yes | meta | google | linkedin |
startDate | Yes | ISO date, e.g. 2026-05-27 |
endDate | Yes | ISO date, e.g. 2026-06-09 |
Validation: The window must be 7–30 days inclusive.
The comparison period (equal-length window immediately before startDate) is
returned automatically as previousPeriod — no second request needed.
Note on rate fields: ctr, cpc, cpm,
and costPerConversion in totals and previousTotals
are recalculated from summed base values, not averaged from daily rates.
Error Responses
All errors return { "error": "ERROR_CODE", "message": "..." }.
| Status | Code | When it occurs |
|---|---|---|
| 400 | MISSING_PARAM | A required parameter is absent |
| 400 | INVALID_NETWORK | network is not meta, google, or linkedin |
| 400 | INVALID_DATE_FORMAT | A date is not in YYYY-MM-DD format |
| 400 | INVALID_DATE_RANGE | endDate is before startDate |
| 400 | WINDOW_TOO_SMALL | Range is fewer than 7 days |
| 400 | WINDOW_TOO_LARGE | Range exceeds 30 days |
| 404 | NOT_FOUND | Path does not match either endpoint |
| 405 | METHOD_NOT_ALLOWED | Non-GET request on either endpoint |
Data Types
SummaryMetrics (summary endpoint only): date, impressions, clicks, spend (USD), conversions.
DailyMetrics (base for all insights): extends SummaryMetrics with ctr (%), cpc (USD), cpm (USD per 1k impressions).
FacebookDailyMetrics: extends DailyMetrics with reach, likes, comments, shares.
InstagramDailyMetrics: extends DailyMetrics with reach, likes, comments, saves.
GoogleDailyMetrics: extends DailyMetrics with costPerConversion (USD; zero when no conversions).
LinkedInDailyMetrics: extends DailyMetrics with likes, comments, shares, follows.
Data Characteristics
The data is synthetically generated on every request — there is no database. Values follow a slow sine-wave trend plus ±15% daily noise.
| Platform | Weekend behavior |
|---|---|
| ~+30% impressions vs. weekdays | |
| ~+45% impressions vs. weekdays | |
| ~−25% impressions vs. weekdays | |
| Drops to ~7% of weekday volume — near-zero weekends are expected, not a bug |
Evaluation
| Criteria | What we're looking at |
|---|---|
| Requirements | All eight required features are present and functional |
| Data accuracy | Metrics display correctly; period-over-period deltas match; rate totals reflect the full period, not an average of daily values |
| UX clarity | A non-technical user could read the dashboard and understand what's happening |
| Loading & error handling | Visible, intentional, and covers all fetch paths |
| Code structure | Data fetching in hooks, components focused on rendering, types used consistently |
| Polish | Does it feel finished? Edge cases handled, nothing obviously broken |
We evaluate what's submitted, not what you planned to do. A smaller, tight implementation outscores a large, unfinished one.
Going Beyond
Some ideas (none required):
- Sortable data tables beneath the charts
- Dark / light theme toggle (persist across sessions)
- Metric tooltips explaining CTR, CPM, Cost/Conv for non-ad users
- Insight callouts surfacing notable observations automatically
- Responsive layout for narrower viewports
- Keyboard navigation — accessible date picker, tab-navigable metric cards
- Animated transitions — loading skeletons, chart fade-ins, smooth tab switches
If you have a genuinely good idea that isn't on this list, build it. We care more about judgment — knowing what to add and what to leave out — than feature count. Bonus work should be clearly bonus; don't sacrifice core requirements to add extras.
Constraints
- The dashboard must run in a browser.
- The three network values (
meta,google,linkedin) and four platforms are fixed — the backend does not support others. - Date ranges sent to
/v1/metrics-insightsmust be 7–30 days; anything outside is rejected with a structured error. - Only
GETrequests are supported;POST,PUT,DELETE, andTRACEreturn405.
How to Submit
When you're ready to turn in your work, choose one of the two methods below and email all three reviewers simultaneously.
Option A — GitHub Repository
- Create a new repository at github.com/new (public or private).
- Push your code:
git push origin main - If the repository is private, invite all three reviewers as collaborators before sending.
- Include the repository URL in your submission email.
Option B — ZIP File
- Archive your project folder as a ZIP.
- Exclude
node_modules/from the archive. - Include a
README.mdwith setup and run instructions. - Name the file
yourname-eulerity-hackathon.zipand attach it to your submission email.
Reviewers — email all three
Email all three reviewers at once — not just one. Include your repository link or ZIP attachment, and a brief note on anything you'd like us to pay special attention to.
If you have any issues with setup, programming questions, or need an extension, feel free to ask!