I'm trying to create a report showing daily conversions from the last 30 days with google analytics data api. This is using the dotnet client library Google.Analytics.Data.V1Beta.
However I'm only getting back about 5 conversion values, the last value seems to be reflecting total conversions of all time, ideally I'd like a running update of how many conversions per day so I can plot it to a line chart.
I'm planning to change this to weekly over the course of the past X months once I have the previous issue sorted out.
I'm essentially trying to recreate the chart on the google analytics dashboard:
What am I missing?
public async Task<RunReportResponse> RunReport(string propertyId = "xxxx")
{
BetaAnalyticsDataClient client = BetaAnalyticsDataClient.Create();
FilterExpression hostnameFilter = new();
hostnameFilter.Filter = new();
hostnameFilter.Filter.InListFilter = new();
hostnameFilter.Filter.InListFilter.Values.Add("xxxx");
hostnameFilter.Filter.FieldName = "hostName";
CohortSpec cohort = new();
cohort.Cohorts.Add(new Cohort
{
Dimension = "firstSessionDate",
DateRange = new DateRange()
{
StartDate = DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd"),
EndDate = DateTime.Now.ToString("yyyy-MM-dd")
},
});
cohort.CohortsRange = new CohortsRange
{
EndOffset = 5,
Granularity = CohortsRange.Types.Granularity.Daily
};
// Initialize request argument(s)
RunReportRequest request = new()
{
Property = "properties/" + propertyId,
Dimensions = {new Dimension { Name = "cohort" }, new Dimension { Name = "cohortNthDay" } },
Metrics = { new Metric { Name = "conversions" }, },
DimensionFilter = hostnameFilter,
CohortSpec = cohort,
};
// Make the request
var response = await client.RunReportAsync(request);
return response;
}
}
Related
I'm writing an application downloading data from Google Analytics in .NET core 3.5 using Google.Apis.AnalyticsReporting.v4.
For some reason direct traffic (rows where sourceMedium is (direct) / (none) ) is not being returned from GA. No filters are applied and the date range is always one day.
Playing around with it I found out that adding time dimension dateHour solves the issue. But it multiplies the number of rows significantly and I really want to avoid that.
Any idea why this request returns all records successfully:
ReportRequest reportRequest = new ReportRequest
{
ViewId = viewId,
//IncludeEmptyRows = true,
DateRanges = new List<DateRange>() { dateRange },
Metrics = new List<Metric>() { sessions, transactions, transactionRevenue },
Dimensions = new List<Dimension>() { date, sourceMedium, campaign, datehour },
//DimensionFilterClauses = new List<DimensionFilterClause>() { dimFilters },
PageSize = 10000,
PageToken = "1"
};
but when deleting the datehour dimension direct traffic (and only direct traffic) is missing from the response?
ReportRequest reportRequest = new ReportRequest
{
ViewId = viewId,
//IncludeEmptyRows = true,
DateRanges = new List<DateRange>() { dateRange },
Metrics = new List<Metric>() { sessions, transactions, transactionRevenue },
Dimensions = new List<Dimension>() { date, sourceMedium, campaign },
//DimensionFilterClauses = new List<DimensionFilterClause>() { dimFilters },
PageSize = 10000,
PageToken = "1"
};
IncludeEmptyRows parameter doesn't have any impact on the outcome.
Any suggestions are welcomed.
The solution for me was to change the date range. When the StartDate and the EndDate are the same day all the traffic is returned except for direct traffic. When StartDate and the EndDate are not the same day all traffic gets returned.
I am using Google.Apis.AnalyticsReporting.v4 library for old google analytics views. How do I convert this code to GA4? I can't find a line about switching View Id to something else in code.
I have checked this post "How do I get view id in GA4", but my properties already exist and I don't see option to modify them after creation.
using (var svc = new AnalyticsReportingService(authInitializer.CreateInitializer()))
{
var dateRange = new DateRange
{
StartDate = analyticsParams.From.ToString("yyyy-MM-dd"),
EndDate = analyticsParams.To.ToString("yyyy-MM-dd")
};
var sessions = new Metric
{
Expression = "ga:sessions",
Alias = "Sessions"
};
var date = new Dimension { Name = "ga:date" };
var reportRequest = new ReportRequest
{
DateRanges = new List<DateRange> { dateRange },
Dimensions = new List<Dimension> { date },
Metrics = new List<Metric> { sessions },
ViewId = analyticsParams.ViewId, // <------------------------- My view id
};
var getReportsRequest = new GetReportsRequest
{
ReportRequests = new List<ReportRequest> { reportRequest }
};
var batchRequest = svc.Reports.BatchGet(getReportsRequest);
var response = batchRequest.Execute();
var reports = response.Reports.First();
return reports.Data.Rows.Select(x => new DataEntry()
{
Date = DateTime.ParseExact(x.Dimensions[0], "yyyyMMdd", CultureInfo.InvariantCulture),
Value = int.Parse(x.Metrics[0].Values[0]),
}).ToList();
}
You need to use the Google Analytics Data API V1 (currently in alpha) in order to access your GA4 properties. Here is a quick start sample for .NET which seems similar to what you are trying to do.
using Google.Analytics.Data.V1Alpha;
using System;
namespace AnalyticsSamples
{
class QuickStart
{
static void SampleRunReport(string propertyId)
{
// Using a default constructor instructs the client to use the credentials
// specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
AlphaAnalyticsDataClient client = AlphaAnalyticsDataClient.Create();
// Initialize request argument(s)
RunReportRequest request = new RunReportRequest
{
Entity = new Entity{ PropertyId = propertyId },
Dimensions = { new Dimension{ Name="city"}, },
Metrics = { new Metric{ Name="activeUsers"}, },
DateRanges = { new DateRange{ StartDate="2020-03-31", EndDate="today"}, },
};
// Make the request
RunReportResponse response = client.RunReport(request);
Console.WriteLine("Report result:");
foreach( Row row in response.Rows )
{
Console.WriteLine("{0}, {1}", row.DimensionValues[0].Value, row.MetricValues[0].Value);
}
}
static int Main(string[] args)
{
if (args.Length == 0 || args.Length > 2)
{
Console.WriteLine("Arguments: <GA4 property ID>");
Console.WriteLine("A GA4 property id parameter is required to make a query to the Google Analytics Data API.");
return 1;
}
string propertyId = args[0];
SampleRunReport(propertyId);
return 0;
}
}
}
Currently there aren't API available for GA4 Property. Furthermore GA4 does not provide Views, you have to use BigQuery to get data programmatically.
Report
I have read this thread: Google Analytics API: Why is the API data different than what's being seen on the Analytics Dashboard? But still cannot figure out why my results differ so much from my Analytics Dashboard.
How can I check in .Net if my response contains sampleData? Here is the code I am using:
string[] s = new string[]{"https://www.googleapis.com/auth/analytics.readonly"};
var auth = GoogleAnalyticsServiceAccount.AuthenticateServiceAccount("XXXXX", "D:\\Spawtz\\Src\\client_id.json", s);
// Create the DateRange object.
//DateRange lastWeek = new DateRange() { StartDate = "2018-12-02", EndDate = "2018-12-09" };
DateRange lastMonth = new DateRange() { StartDate = "2018-11-09", EndDate = "2018-12-09" };
DateRange lastYear = new DateRange() { StartDate = "2017-12-09", EndDate = "2018-12-09" };
// Create the Metrics object.
Metric pageViews = new Metric { Expression = "ga:pageViews"};
//Create the Dimensions object.
Dimension pagePath = new Dimension { Name = "ga:pagePath" };
// Create the ReportRequest object.
// Create the ReportRequest object.
ReportRequest reportRequest = new ReportRequest
{
ViewId = "XXXXX",
DateRanges = new List<DateRange>() { lastMonth, lastYear},
Dimensions = new List<Dimension>() { pagePath },
Metrics = new List<Metric>() { pageViews },
FiltersExpression = "ga:pagePath==/cricket-player/t20/playerid=2348"
};
List<ReportRequest> requests = new List<ReportRequest>();
requests.Add(reportRequest);
// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest() { ReportRequests = requests };
// Call the batchGet method.
GetReportsResponse response = auth.Reports.BatchGet(getReport).Execute();
Can I set the SamplingLevel and Max-Results in asp.Net?
Yes you can set up the Sampling level for your report. It should be something like this Let me know if it doesnt work i can test it.
ReportRequest reportRequest = new ReportRequest
{
ViewId = "XXXXX",
DateRanges = new List<DateRange>() { lastMonth, lastYear},
Dimensions = new List<Dimension>() { pagePath },
Metrics = new List<Metric>() { pageViews },
isDataGolden
The response data for each report should return a value called isDataGolden if the data is completed processing.
TIP
Remember that your request in the dashboard must be exactly the same as the request you are making to the API if you want the data to be the same. The exact same dimensions, metrics and dates. You cant look at a report in the dashbaord that contains five dimensions and then make a request to the api only looking at pageviews the numbers will not add up.
FiltersExpression = "ga:pagePath==/cricket-player/t20/playerid=2348"
Sampling = "SAMPLINGUNSPECIFIED"
};
Update
According to the picture you posted you are looking at a report with the following dimensions and metrics.
page
pageviews
uniquepageviews
avg time on page
Entrances
bournce rate
% Exit
page value
Your request to the api must make the exact same request which means you need to use the exact same dimensions and metrics.
I'm using the Google Anayltics Reporting API v4 to query page views on my site, ordered by most viewed. I discovered that I'm getting duplicate entries, where the path is the same but the capitalization is different
DateRange dateRange = new DateRange()
{
StartDate = startDate.ToString("yyyy-MM-dd"),
EndDate = DateTime.Now.ToString("yyyy-MM-dd")
};
// Create the Metrics object.
Metric pageviews = new Metric {Expression = "ga:pageviews", Alias = "Pageviews"};
//Create the Dimensions object.
Dimension path = new Dimension { Name = "ga:pagePath" };
OrderBy orderby = new OrderBy {FieldName = "ga:pageviews", SortOrder = "DESCENDING"};
// Create the ReportRequest object.
ReportRequest reportRequest = new ReportRequest
{
ViewId = viewId,
DateRanges = new List<DateRange>() { dateRange },
Dimensions = new List<Dimension>() { path },
Metrics = new List<Metric>() { pageviews },
OrderBys = new List<OrderBy>() { orderby }
};
List<ReportRequest> requests = new List<ReportRequest>();
requests.Add(reportRequest);
// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest() { ReportRequests = requests };
// Call the batchGet method.
GetReportsResponse response = svc.Reports.BatchGet(getReport).Execute();
foreach (var report in response.Reports)
{
var data = report.Data.Rows.Select(x => new AnalyticsPage
{
Path = x.Dimensions[0],
Views = Convert.ToInt32(x.Metrics[0].Values[0])
});
pages.AddRange(data);
}
When I view my results, pages[41] is "/events/tech-knowledge" (3150 page views) and pages[429] is "/Events/Tech-Knowledge" (200 page views)
Is there something I can add to my query to make the API ignore case in the path field? I know I could modify my code to combine entries where the path.ToLower() is the same, but it would be better to get the API to return the data correctly
Checked the Analytics API reference, no such ready made filter. I suggest proceeding with your workaround.
How do i get the CPU usage of an instance in c#?
I've read Amazon EC2 - how to get available ram and cpu usage via AWS API? already, but i can't get it working.
NameValueCollection appConfig = ConfigurationManager.AppSettings;
var client = AWSClientFactory.CreateAmazonCloudWatchClient(
appConfig["AWSAccessKey"],
appConfig["AWSSecretKey"]
);
var dimension = new Dimension
{
Name = "InstanceId",
Value = "<i-ad20b4db>",
};
var request = new GetMetricStatisticsRequest();
request.MetricName = "CPUUtilization";
request.Period = 60;
request.Statistics.Add("Maximum");
request.Dimensions.Add(dimension);
request.Namespace = "AWS/EC2";
request.Unit = "Percent";
var currentTime = DateTime.UtcNow;
var startTime = currentTime.AddSeconds(-5);
string currentTimeString= currentTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
string startTimeString= startTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
request.StartTime = Convert.ToDateTime( startTimeString);
request.EndTime = Convert.ToDateTime(currentTimeString);
var response = client.GetMetricStatistics(request);
if ( response.GetMetricStatisticsResult.Datapoints.Count > 0)
{
var dataPoint = response.GetMetricStatisticsResult.Datapoints[0];
Console.WriteLine( "Instance: {0} CPU Max load: {1}", dimension.Value, dataPoint.Maximum);
}
Here's a simple proof of concept for showing the CPU Utilization during the last two days. I think there will be a datapoint like every half an hour, but you can easily change by changing the value of the Period property in the GetMetricStatisticsRequest object.
AmazonCloudWatch cw = AWSClientFactory.CreateAmazonCloudWatchClient(accessKey, secretKey, new AmazonCloudWatchConfig().WithServiceURL("https://eu-west-1.monitoring.amazonaws.com"));
DataTable data = new DataTable();
try
{
Dimension dim = new Dimension() { Name = "InstanceId", Value = GetInstanceName(amazonInstance) };
System.Collections.Generic.List<Dimension> dimensions = new List<Dimension>() { dim };
string startTime = startTime = DateTimeOffset.Parse(DateTime.Now.AddDays(-2).ToString()).ToUniversalTime().ToString("s"); // "2010-09-29T11:00:00+01:00";
GetMetricStatisticsRequest reg = new GetMetricStatisticsRequest()
{
MeasureName = "CPUUtilization",
Period = 1800
Statistics = new System.Collections.Generic.List<string>() { "Average" },
Dimensions = dimensions,
Namespace = "AWS/EC2",
EndTime = DateTime.Now.ToUniversalTime().ToString("s"), //has to be in this format: 2010-09-29T14:00:00+01:00;
StartTime = startTime
};
var points = cw.GetMetricStatistics(reg).GetMetricStatisticsResult.Datapoints.OrderBy(p => p.Timestamp);
data.Columns.Add("Average");
data.Columns.Add("TimeStamp");
foreach (var p in points)
{
DataRow row = data.NewRow();
row["Average"] = Math.Round(p.Average, 0);
row["TimeStamp"] = DateTimeOffset.Parse(p.Timestamp).LocalDateTime.ToString("yyyy-MM-dd HH:mm");
data.Rows.Add(row);
}
}
catch (AmazonCloudWatchException ex)
{
if (ex.ErrorCode.Equals("OptInRequired"))
throw new Exception("You are not signed in for Amazon EC2.");
else
throw;
}
This is my final code which works for me.
I have added new user in the IAM aws management console then i have Attached CloudWatchfullacess Policy to new user then i have used this user Accesskey & secret key in this Code.
var cw =AWSClientFactory.CreateAmazonCloudWatchClient("AccessKey","secretkey",Amazon.RegionEndpoint.USWest2);
DataTable data = new DataTable();
try
{
Dimension dim = new Dimension() { Name = "InstanceId", Value = "InstanceId of you EC2 Server" };
System.Collections.Generic.List<Dimension> dimensions = new List<Dimension>() { dim };
string startTime1 = DateTimeOffset.Parse(DateTime.Now.AddMinutes(-60).ToString()).ToUniversalTime().ToString("s");
GetMetricStatisticsRequest reg = new GetMetricStatisticsRequest()
{
MetricName = "CPUUtilization",
Period = 60,
Statistics = new System.Collections.Generic.List<string>() { "Average","Minimum","Maximum" },
Dimensions = dimensions,
Namespace = "AWS/EC2",
EndTime = DateTime.Now, //Convert.ToDateTime(DateTime.Now.ToUniversalTime().ToString("s")), //has to be in this format: 2010-09-29T14:00:00+01:00;
StartTime = DateTime.Now.AddHours(Convert.ToInt32(-15)),// Convert.ToDateTime(startTime1),
};
var points = cw.GetMetricStatistics(reg).GetMetricStatisticsResult.Datapoints.OrderBy(p => p.Timestamp);
data.Columns.Add("Average");
data.Columns.Add("TimeStamp");
foreach (var p in points)
{
DataRow row = data.NewRow();
row["Average"] = Math.Round(p.Average, 0);
row["TimeStamp"] = p.Timestamp; //DateTimeOffset.Parse(Convert.ToDateTime(p.Timestamp)).LocalDateTime.ToString("yyyy-MM-dd HH:mm");
data.Rows.Add(row);
}
dataGridView1.DataSource = data;
}
catch (AmazonCloudWatchException ex)
{
if (ex.ErrorCode.Equals("OptInRequired"))
throw new Exception("You are not signed in for Amazon EC2.");
else
throw;
}
Pleas also note that when you want to get CPU usage or any other type of metric, you should be wary of the time-stamp you include in the request. This is because it can take more than 48 hours for data to become available in CloudWatch (according to Amazon).
That is why I personally try to retrieve data from about 3-4 days ago as sometimes CloudWatch will not return any data even if the request and the code are all correct as it does not have any data to publish from the previous day or two.
For more information check this URL and scroll down to StartTime: http://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_GetMetricStatistics.html