I Pulled Nine Years of My Own Dev.to Data. The Numbers Were Not What I Expected.
Dev.to 9년치 데이터를 API로 분석했더니 예상과 달랐습니다
Dev.to API로 팔로워와 게시물 데이터를 모아 9년간의 활동을 비교했습니다. 팔로워 수와 조회수는 독자 반응을 제대로 나타내지 않았고, 오래된 분석 데이터에는 누락이 있어 지표를 해석할 때 데이터 범위와 댓글 깊이를 살펴야 한다고 설명합니다.
- 주제
AI 요약
2017년부터 Dev.to에 글을 올린 저자는 4년 가까이 활동이 뜸했던 시기를 지나 2026년 3월부터 6개월 동안 글 86편을 게시했습니다. 한 계정에서 시차를 두고 쌓인 두 시기의 글을 비교하면서, 대시보드에 보이지 않는 정보를 API에서 얻고 각 지표가 실제로 무엇을 나타내는지 살펴봅니다.
API 호출과 팔로워 데이터
Dev.to API 기본 주소는 https://dev.to/api입니다. 설정의 Extensions에서 API 키를 발급하고, 대부분의 본인 데이터 조회 요청에 api-key 헤더를 넣습니다. 저자는 Accept: application/vnd.forem.api-v1+json 헤더를 빠뜨리면 오류 없이 구형 v0 응답을 받는다고 경고합니다. 문서에 나온 필드가 없을 때 먼저 API 버전 헤더를 확인해야 합니다.
팔로워 조회 API는 페이지당 80명을 기본값으로 안내하지만, v1에서는 per_page=1000을 요청할 수 있습니다. 팔로워가 1만 8천 명이 넘는 저자의 경우 요청 횟수는 227회에서 19회로 줄었고, 전체 조회에는 31초가 걸렸습니다. Forem 인스턴스 설정에 따라 서버가 페이지 크기를 더 낮게 제한할 수 있으므로, 요청값을 그대로 가정하지 말고 첫 응답의 실제 항목 수를 확인하라고 제안합니다. 요청 제한에 걸리는 429 응답에는 대기 후 재시도하고, 여러 페이지를 가져오는 동안 병합 결과를 디스크에 저장해야 중간 실패로 앞선 데이터를 잃지 않습니다.
/api/followers/users 응답에는 각 팔로워의 created_at이 담깁니다. 현재 팔로우 중인 계정의 날짜를 모으면 과거에 별도로 저장하지 않은 팔로워 유입 곡선을 한 번의 조회로 재구성할 수 있습니다. 다만 이 곡선은 특정 날짜 당시의 팔로워 수가 아닙니다. 현재도 팔로우 중인 사람만 남으므로, 나중에 언팔로우했거나 계정이 삭제된 사람은 빠집니다. 저자는 이를 ‘유입 시점별 현재 팔로워’로 구분합니다. 게시물과 팔로워 유입을 비교할 때는 참고가 되지만, 유지율이나 과거의 실제 팔로워 수를 분석하는 데 쓰면 오해를 낳습니다.
분석 API와 누락 데이터
저자는 /api/analytics/totals, /api/analytics/historical, /api/analytics/past_day, /api/analytics/referrers, /api/analytics/follower_engagement, /api/analytics/dashboard를 소개합니다. 각 API는 article_id로 게시물 하나를 지정할 수 있습니다. 응답은 평탄한 숫자가 아니라 page_views.total처럼 중첩된 구조로 돌아옵니다.
과거 데이터는 시점에 따라 완전성이 다릅니다. 2017년 게시물은 분석 API의 기록이 전체 평생 조회수의 약 15%에 그쳤고, 2019년 게시물은 95%, 2026년 게시물은 100%를 포함했습니다. 저자는 게시물이 조회수의 절반을 얻기까지 걸린 날짜를 ‘반감기’로 계산했다가, 2017년 글 몇 편의 값이 약 3,000일로 나오자 데이터 누락을 발견했습니다. 기록된 일부 조회수만으로 계산하면 그럴듯하지만 잘못된 결과가 나옵니다. 그래서 전체 조회수 가운데 분석 시계열이 80% 미만을 설명하는 글은 계산에서 제외했습니다. 글 130편 중 82편이 기준을 통과했고, 해당 글의 반감기 중앙값은 4일이었습니다.
글 묶음과 댓글 구조
게시물 응답에는 시리즈를 묶는 데 쓸 법한 collection_id가 없었습니다. 하지만 /api/articles/me/published에서 body_markdown을 가져오면 본문 앞부분의 YAML front matter에 적힌 series: 값을 읽을 수 있습니다. 기대한 필드가 JSON에 없을 때 원문 본문이 함께 반환되는지 확인하라는 설명입니다.
/api/comments?a_id={id}는 댓글과 답글을 children에 중첩해 반환합니다. 이를 재귀적으로 펼치면서 깊이, 작성자, 작성 시각, 댓글 내용을 보존할 수 있습니다. 저자는 댓글 수보다 스레드 깊이가 대화의 성격을 더 잘 드러낸다고 봅니다. ‘좋은 글’ 같은 댓글 여덟 개와 여러 차례 반박을 주고받은 대화는 개수가 같아도 다르기 때문입니다. 한 게시물에는 깊이가 35단계인 스레드도 있었습니다.
조회수와 독자 반응은 다른 지표입니다
저자는 2026년에 팔로워 약 1만 8천 명을 얻었지만, 같은 해 게시물의 합산 조회수는 1만 4,300회였습니다. 일일 팔로워 증가량 중앙값은 136명이었고 게시물 발행 여부에 따른 뚜렷한 차이가 없었습니다. 사용자 이름 약 37%에는 자동 생성된 듯한 16진수 또는 숫자 꼬리가 붙어 있었습니다. 저자는 이를 상호 팔로우를 늘리는 활동으로 보고, 팔로워 수만으로 독자 규모를 판단할 수 없다고 말합니다.
2017~2019년 글 44편은 조회수 3만 2,474회를 얻었지만 댓글은 모두 26개였습니다. 2026년 글 86편은 조회수 1만 4,300회에 댓글 606개를 기록했습니다. 오래된 MicroPython, NodeMCU, MongoDB 튜토리얼은 조회수 1천 회당 반응이 약 2개였고, 2026년 에세이는 56~72개였습니다. 조회수 5,472회를 기록한 NodeMCU 글은 최근 90일 동안 조회가 없었으며, 전체 130편 중 19편은 해당 분기 조회수가 0이었습니다. 평생 조회수는 줄지 않으므로, 누적 수치만 보면 이미 읽히지 않는 글도 계속 활동하는 듯 보입니다.
트래픽 유입 경로에서 Google은 4%, 직접 유입 또는 출처 미상은 74.5%, Dev.to 내부 유입은 19%였습니다. 저자는 조회수와 팔로워 수처럼 콘텐츠의 배포 규모를 나타내는 지표와, 댓글 깊이·답글 비율처럼 독자의 참여를 나타내는 지표를 따로 봐야 한다고 정리합니다. 팔로워 데이터를 주기적으로 저장하면 이후 언팔로우 변화를 추적할 수 있고, 분석 계산에 앞서 시계열의 데이터 범위를 확인해야 합니다.
dev.to 반응
- @naveen_alavilli —
created_at으로 유입 곡선을 재구성하는 방법은 유용하지만, 그 곡선으로 결론을 내리기 전에 편향을 분명히 밝혀야 합니다./followers/users에는 현재 팔로우 중인 사람만 나오므로 2018년에 팔로우했다가 2021년에 떠난 사람이나 계정이 삭제된 사람은 빠집니다. 따라서 재구성한 시계열은 ‘날짜 X에 보유했던 팔로워’가 아니라 ‘날짜 X까지 팔로우를 시작했고 지금도 남아 있는 사람’입니다. 2017~2020년의 초기 팔로워는 이탈할 시간이 더 길었고, 2026년 복귀 시기의 팔로워는 몇 달밖에 지나지 않았습니다. 이탈이 초기 구간에서 더 많이 빠져나가므로 2017~2020년 곡선은 낮아지고 2026년 복귀 구간은 실제보다 더 가파르게 보입니다. 글 86편의 실제 효과가 무엇이든 재구성 결과는 그 효과를 과장하는 쪽으로 치우칩니다. 해결책은 간단합니다. 조회할 때마다 결과를 날짜와 함께 저장하고 팔로워 ID 집합을 보관하세요. 두 번의 결과를 비교하면 이탈을 직접 측정할 수 있고, 몇 달 뒤에는 오래된 집단의 이탈률을 계산해 누락된 부분을 모델링할 근거가 생깁니다. 한 번의 스냅샷은 모양을 복원하고, 두 번의 스냅샷부터는 그 모양이 얼마나 실제에 가까운지 알 수 있습니다.Accept헤더 문제도 마찬가지입니다. 오류 대신 그럴듯한 응답을 돌려주는 조용한 v0 대체는 최악의 API 실패입니다. 스크립트 초반에 v1에서만 나오는 필드가 있는지 확인하고, 없으면 명확한 오류를 내도록 하세요. 그러지 않으면 잘못된 헤더를 알아차리기 전에 세 시간 뒤 차트의 차원이 빠진 것을 발견하게 됩니다.- @kenwalger — 집단별 이탈률 차이를 지적해 주셔서 감사합니다. 재구성한 곡선이 ‘과거의 팔로워 수’가 아니라 ‘유입 시점별 현재 팔로워’라고 밝히기는 했지만, 오래된 구간과 최근 구간을 비교할 때 생기는 한계까지 명시적으로 적용하지는 않았습니다. 오래된 집단은 팔로워를 잃을 시간이 훨씬 길었습니다. 앞으로 스냅샷을 저장하자는 제안도 좋습니다. API에서 이미 사라진 과거 이탈자를 되살릴 수는 없으니, 향후 이탈을 측정하고 시간이 지나며 과거 누락분을 모델링할 자료를 모으는 방법이라고 설명하겠습니다. 지금부터 ID 집합을 저장할 이유가 하나 더 생겼습니다. API가 조용히 v0으로 돌아갈 때 명확하게 실패시키자는 의견에도 동의합니다. 버전별 필드 확인을 했다면 한참 헤매지 않았을 겁니다.
원문: dev.to / 번역·요약: Trawling